@staticforge/iac 0.0.0-stage → 0.1.1

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.
@@ -0,0 +1,78 @@
1
+ import { type Logger } from '@staticforge/core';
2
+ import type { Engine } from './engine.js';
3
+ /** A workspace and the engine that runs it. */
4
+ export interface Workspace {
5
+ engine: Engine;
6
+ dir: string;
7
+ env: NodeJS.ProcessEnv;
8
+ logger: Logger;
9
+ }
10
+ export type ChangeAction = 'create' | 'update' | 'delete' | 'replace' | 'read' | 'noop' | 'move';
11
+ export interface ResourceChange {
12
+ address: string;
13
+ action: ChangeAction;
14
+ }
15
+ export interface PlanSummary {
16
+ /** True when applying the plan would change something. */
17
+ changes: boolean;
18
+ add: number;
19
+ change: number;
20
+ remove: number;
21
+ import: number;
22
+ resources: ResourceChange[];
23
+ /** Changes made outside OpenTofu/Terraform, detected while refreshing. */
24
+ drift: ResourceChange[];
25
+ /** Saved plan file (absent for refresh-only and failed plans). */
26
+ planFile?: string;
27
+ }
28
+ export interface ApplySummary {
29
+ add: number;
30
+ change: number;
31
+ remove: number;
32
+ }
33
+ export interface OutputValue {
34
+ value: unknown;
35
+ sensitive: boolean;
36
+ type?: unknown;
37
+ }
38
+ /** Platforms recorded in `.terraform.lock.hcl`, so a lock made on a laptop also works in CI. */
39
+ export declare const LOCK_PLATFORMS: string[];
40
+ export interface InitOptions {
41
+ /** `-migrate-state -force-copy`: move existing state into the configured backend. */
42
+ migrateState?: boolean;
43
+ /** `-reconfigure`: use the configured backend, ignoring the previous one. */
44
+ reconfigure?: boolean;
45
+ /** `-backend=false`: install modules and providers only (for validate). */
46
+ noBackend?: boolean;
47
+ }
48
+ /**
49
+ * `init`. The first init also records provider checksums for the common
50
+ * platforms in `.terraform.lock.hcl`.
51
+ */
52
+ export declare function init(ws: Workspace, options?: InitOptions): Promise<void>;
53
+ export interface PlanOptions {
54
+ /** Only compare the state with the real infrastructure (drift detection). */
55
+ refreshOnly?: boolean;
56
+ destroy?: boolean;
57
+ /** Plan file to write (relative to the workspace). Defaults to `tfplan`. */
58
+ out?: string;
59
+ /** Only these resource addresses (`-target`). */
60
+ targets?: string[];
61
+ }
62
+ /** `plan -detailed-exitcode`: 0 no changes, 2 changes, anything else failed. */
63
+ export declare function plan(ws: Workspace, options?: PlanOptions): Promise<PlanSummary>;
64
+ /** Apply a saved plan. */
65
+ export declare function apply(ws: Workspace, planFile: string): Promise<ApplySummary>;
66
+ /**
67
+ * `apply -refresh-only`: record attributes the provider only reports after
68
+ * creation (a function's status, a bucket's policy, empty lists). Run right
69
+ * after an apply, so `sforge status` reports only real drift.
70
+ */
71
+ export declare function refreshState(ws: Workspace): Promise<void>;
72
+ /** `output -json`: every root output, sensitive ones included (callers must filter). */
73
+ export declare function outputs(ws: Workspace): Promise<Record<string, OutputValue>>;
74
+ /** Non-sensitive output values, keyed by name. */
75
+ export declare function publicOutputs(values: Record<string, OutputValue>): Record<string, unknown>;
76
+ /** Whether a workspace holds local state (only with --local-state or a pending bootstrap). */
77
+ export declare function hasLocalState(dir: string): boolean;
78
+ //# sourceMappingURL=operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../src/operations.ts"],"names":[],"mappings":"AAEA,OAAO,EAAa,KAAK,MAAM,EAAe,MAAM,mBAAmB,CAAC;AACxE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAG1C,+CAA+C;AAC/C,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEjG,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,0DAA0D;IAC1D,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,0EAA0E;IAC1E,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,gGAAgG;AAChG,eAAO,MAAM,cAAc,UAM1B,CAAC;AAiCF,MAAM,WAAW,WAAW;IAC1B,qFAAqF;IACrF,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAsB,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BlF;AAgCD,MAAM,WAAW,WAAW;IAC1B,6EAA6E;IAC7E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4EAA4E;IAC5E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,gFAAgF;AAChF,wBAAsB,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CAczF;AAED,0BAA0B;AAC1B,wBAAsB,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAKlF;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAS/D;AAED,wFAAwF;AACxF,wBAAsB,OAAO,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAYjF;AAED,kDAAkD;AAClD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAM1F;AAED,8FAA8F;AAC9F,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CASlD"}
@@ -0,0 +1,185 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { ErrorCode, SforgeError } from '@staticforge/core';
4
+ import { assertSucceeded, runEngine } from './runner.js';
5
+ /** Platforms recorded in `.terraform.lock.hcl`, so a lock made on a laptop also works in CI. */
6
+ export const LOCK_PLATFORMS = [
7
+ 'linux_amd64',
8
+ 'linux_arm64',
9
+ 'darwin_amd64',
10
+ 'darwin_arm64',
11
+ 'windows_amd64',
12
+ ];
13
+ /** Log engine progress: resource operations at info, the rest at debug. */
14
+ function progressLogger(logger) {
15
+ return (event) => {
16
+ if (event.message === '')
17
+ return;
18
+ switch (event.type) {
19
+ case 'apply_start':
20
+ case 'apply_complete':
21
+ case 'apply_errored':
22
+ case 'resource_drift':
23
+ logger.info(event.message);
24
+ break;
25
+ case 'diagnostic':
26
+ if (event.level === 'warn')
27
+ logger.warn(event.message);
28
+ else
29
+ logger.debug(event.message);
30
+ break;
31
+ default:
32
+ logger.debug(event.message);
33
+ }
34
+ };
35
+ }
36
+ function run(ws, args, json = true) {
37
+ ws.logger.debug(`${ws.engine.name} ${args.join(' ')}`);
38
+ return runEngine(ws.engine, args, {
39
+ cwd: ws.dir,
40
+ env: ws.env,
41
+ json,
42
+ onEvent: progressLogger(ws.logger),
43
+ });
44
+ }
45
+ /**
46
+ * `init`. The first init also records provider checksums for the common
47
+ * platforms in `.terraform.lock.hcl`.
48
+ */
49
+ export async function init(ws, options = {}) {
50
+ const lockFile = join(ws.dir, '.terraform.lock.hcl');
51
+ const hadLock = existsSync(lockFile);
52
+ const args = ['init', '-input=false', '-no-color'];
53
+ if (options.migrateState)
54
+ args.push('-migrate-state', '-force-copy');
55
+ if (options.reconfigure)
56
+ args.push('-reconfigure');
57
+ if (options.noBackend)
58
+ args.push('-backend=false');
59
+ const result = await run(ws, args, false);
60
+ if (result.exitCode !== 0 &&
61
+ /backend configuration (has )?changed/i.test(result.stdout + result.stderr)) {
62
+ throw new SforgeError(ErrorCode.IacFailed, 'The state backend configuration changed', {
63
+ details: { diagnostics: result.diagnostics },
64
+ hint: 'Move the state with `sforge iac init <target> -- -migrate-state`, ' +
65
+ 'or start over in the new backend with `-- -reconfigure`.',
66
+ });
67
+ }
68
+ assertSucceeded(result, `${ws.engine.name} init`);
69
+ if (!hadLock && existsSync(lockFile)) {
70
+ const lock = await run(ws, ['providers', 'lock', ...LOCK_PLATFORMS.map((p) => `-platform=${p}`)], false);
71
+ // Not fatal: the lock still covers the current platform.
72
+ if (lock.exitCode !== 0)
73
+ ws.logger.warn('Could not add other platforms to .terraform.lock.hcl');
74
+ }
75
+ }
76
+ function change(raw) {
77
+ const c = raw.change;
78
+ if (c?.resource?.addr === undefined || c.action === undefined)
79
+ return undefined;
80
+ return { address: c.resource.addr, action: c.action };
81
+ }
82
+ function summarize(result) {
83
+ const resources = [];
84
+ const drift = [];
85
+ let counts = { add: 0, change: 0, remove: 0, import: 0 };
86
+ for (const event of result.events) {
87
+ if (event.type === 'planned_change') {
88
+ const c = change(event.raw);
89
+ if (c !== undefined)
90
+ resources.push(c);
91
+ }
92
+ else if (event.type === 'resource_drift') {
93
+ const c = change(event.raw);
94
+ if (c !== undefined)
95
+ drift.push(c);
96
+ }
97
+ else if (event.type === 'change_summary') {
98
+ const c = event.raw.changes;
99
+ counts = {
100
+ add: c?.add ?? 0,
101
+ change: c?.change ?? 0,
102
+ remove: c?.remove ?? 0,
103
+ import: c?.import ?? 0,
104
+ };
105
+ }
106
+ }
107
+ return { ...counts, resources, drift };
108
+ }
109
+ /** `plan -detailed-exitcode`: 0 no changes, 2 changes, anything else failed. */
110
+ export async function plan(ws, options = {}) {
111
+ const out = options.out ?? 'tfplan';
112
+ const args = ['plan', '-input=false', '-json', '-detailed-exitcode', `-out=${out}`];
113
+ if (options.refreshOnly)
114
+ args.push('-refresh-only');
115
+ if (options.destroy)
116
+ args.push('-destroy');
117
+ for (const target of options.targets ?? [])
118
+ args.push(`-target=${target}`);
119
+ const result = await run(ws, args);
120
+ assertSucceeded(result, `${ws.engine.name} plan`, [0, 2]);
121
+ const summary = summarize(result);
122
+ return {
123
+ ...summary,
124
+ changes: result.exitCode === 2,
125
+ ...(result.exitCode === 2 && { planFile: out }),
126
+ };
127
+ }
128
+ /** Apply a saved plan. */
129
+ export async function apply(ws, planFile) {
130
+ const result = await run(ws, ['apply', '-input=false', '-json', planFile]);
131
+ assertSucceeded(result, `${ws.engine.name} apply`);
132
+ const summary = summarize(result);
133
+ return { add: summary.add, change: summary.change, remove: summary.remove };
134
+ }
135
+ /**
136
+ * `apply -refresh-only`: record attributes the provider only reports after
137
+ * creation (a function's status, a bucket's policy, empty lists). Run right
138
+ * after an apply, so `sforge status` reports only real drift.
139
+ */
140
+ export async function refreshState(ws) {
141
+ const result = await run(ws, [
142
+ 'apply',
143
+ '-refresh-only',
144
+ '-auto-approve',
145
+ '-input=false',
146
+ '-json',
147
+ ]);
148
+ assertSucceeded(result, `${ws.engine.name} apply -refresh-only`);
149
+ }
150
+ /** `output -json`: every root output, sensitive ones included (callers must filter). */
151
+ export async function outputs(ws) {
152
+ const result = await run(ws, ['output', '-json', '-no-color'], false);
153
+ assertSucceeded(result, `${ws.engine.name} output`);
154
+ const text = result.stdout.trim();
155
+ if (text === '')
156
+ return {};
157
+ try {
158
+ return JSON.parse(text);
159
+ }
160
+ catch (error) {
161
+ throw new SforgeError(ErrorCode.IacFailed, `Could not parse ${ws.engine.name} output -json`, {
162
+ cause: error,
163
+ });
164
+ }
165
+ }
166
+ /** Non-sensitive output values, keyed by name. */
167
+ export function publicOutputs(values) {
168
+ return Object.fromEntries(Object.entries(values)
169
+ .filter(([, output]) => !output.sensitive)
170
+ .map(([name, output]) => [name, output.value]));
171
+ }
172
+ /** Whether a workspace holds local state (only with --local-state or a pending bootstrap). */
173
+ export function hasLocalState(dir) {
174
+ const path = join(dir, 'terraform.tfstate');
175
+ if (!existsSync(path))
176
+ return false;
177
+ try {
178
+ const state = JSON.parse(readFileSync(path, 'utf8'));
179
+ return (state.resources?.length ?? 0) > 0;
180
+ }
181
+ catch {
182
+ return true;
183
+ }
184
+ }
185
+ //# sourceMappingURL=operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.js","sourceRoot":"","sources":["../src/operations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,128 @@
1
+ import { type Logger } from '@staticforge/core';
2
+ import type { SforgeConfig } from '@staticforge/core';
3
+ import { type Engine, type EngineName } from './engine.js';
4
+ import { type ApplySummary, type PlanSummary, type Workspace } from './operations.js';
5
+ import { type RunResult } from './runner.js';
6
+ import type { IacProfile, PreparedTarget, StateBackend } from './spec.js';
7
+ /** `.sforge/state/<target>.json`: the non-secret outputs of the last apply. */
8
+ export declare function stateCachePath(rootDir: string, targetName: string): string;
9
+ export interface CachedOutputs {
10
+ target: string;
11
+ provider: string;
12
+ engine: EngineName;
13
+ updatedAt: string;
14
+ outputs: Record<string, unknown>;
15
+ }
16
+ export declare function readCachedOutputs(rootDir: string, targetName: string): CachedOutputs | undefined;
17
+ /** Asked before applying; resolves false to abort. */
18
+ export type Confirm = (question: string, plan: PlanSummary) => Promise<boolean>;
19
+ export interface IacRunOptions {
20
+ rootDir: string;
21
+ config: SforgeConfig;
22
+ targetName: string;
23
+ profile: IacProfile;
24
+ env?: NodeJS.ProcessEnv;
25
+ logger: Logger;
26
+ /** Keep state in the workspace instead of the remote backend. */
27
+ localState?: boolean;
28
+ /** Extra module inputs for this run. */
29
+ inputs?: Record<string, unknown>;
30
+ /** Engine to use instead of resolving one (tests). */
31
+ engine?: Engine;
32
+ purpose?: 'provision' | 'outputs';
33
+ }
34
+ interface Opened {
35
+ engine: Engine;
36
+ prepared: PreparedTarget;
37
+ ws: Workspace;
38
+ }
39
+ export interface BootstrapResult {
40
+ backend: string;
41
+ description: string;
42
+ created: boolean;
43
+ }
44
+ /**
45
+ * Create the remote state backend: apply the bootstrap module with local
46
+ * state, then migrate that state into the backend it created. An existing
47
+ * backend is left alone, so bootstrapping is safe to repeat.
48
+ */
49
+ export declare function bootstrapState(options: Omit<IacRunOptions, 'profile' | 'localState'> & {
50
+ engine: Engine;
51
+ state: StateBackend;
52
+ confirm?: Confirm;
53
+ }): Promise<BootstrapResult>;
54
+ export interface ProvisionResult {
55
+ target: string;
56
+ provider: string;
57
+ engine: {
58
+ name: EngineName;
59
+ version: string;
60
+ };
61
+ workspace: string;
62
+ bootstrap?: BootstrapResult;
63
+ plan: PlanSummary;
64
+ /** False for --diff, when nothing changed, or when declined. */
65
+ applied: boolean;
66
+ apply?: ApplySummary;
67
+ outputs?: Record<string, unknown>;
68
+ /** Instructions for the user, e.g. DNS records to create. */
69
+ notices: string[];
70
+ /** True when provisioning stopped after the pre-phase (`noWait`). */
71
+ pending?: boolean;
72
+ }
73
+ export interface ProvisionOptions extends IacRunOptions {
74
+ /** Only plan (`provision --diff`). */
75
+ diff?: boolean;
76
+ /** Create the remote state backend first. */
77
+ bootstrapState?: boolean;
78
+ /** Asked before applying; omit to apply without asking (--yes). */
79
+ confirm?: Confirm;
80
+ /** Stop after the pre-phase instead of waiting for it (e.g. for DNS validation). */
81
+ noWait?: boolean;
82
+ }
83
+ /** `sforge provision`: plan, and unless `diff`, apply after confirmation. */
84
+ export declare function provision(options: ProvisionOptions): Promise<ProvisionResult>;
85
+ /**
86
+ * The target's non-secret outputs: from `.sforge/state/<target>.json`, or
87
+ * (e.g. in CI, where that cache is not committed) read from the state.
88
+ */
89
+ export declare function targetOutputs(options: IacRunOptions): Promise<Record<string, unknown>>;
90
+ export interface DriftResult {
91
+ target: string;
92
+ provider: string;
93
+ engine: {
94
+ name: EngineName;
95
+ version: string;
96
+ };
97
+ /** Resources changed outside OpenTofu/Terraform since the last apply. */
98
+ drift: PlanSummary['drift'];
99
+ drifted: boolean;
100
+ outputs: Record<string, unknown>;
101
+ }
102
+ /** `sforge status`: a refresh-only plan, reporting drift and the current outputs. */
103
+ export declare function detectDrift(options: IacRunOptions): Promise<DriftResult>;
104
+ export interface DestroyResult {
105
+ target: string;
106
+ provider: string;
107
+ plan: PlanSummary;
108
+ destroyed: boolean;
109
+ }
110
+ /** `sforge destroy`: remove every resource of the target (the state backend stays). */
111
+ export declare function destroy(options: IacRunOptions & {
112
+ confirm?: Confirm;
113
+ }): Promise<DestroyResult>;
114
+ export type PassthroughCommand = 'init' | 'plan' | 'apply' | 'output' | 'validate' | 'state' | 'import' | 'show' | 'console';
115
+ /** Generate the workspace and return it, for `sforge iac path` and the passthrough commands. */
116
+ export declare function prepareWorkspace(options: IacRunOptions): Promise<Opened>;
117
+ /** `sforge iac <command> <target> [-- args]`: run the engine directly in the workspace. */
118
+ export declare function passthrough(options: IacRunOptions & {
119
+ command: PassthroughCommand;
120
+ args: string[];
121
+ onStdout: (chunk: string) => void;
122
+ onStderr: (chunk: string) => void;
123
+ interactive: boolean;
124
+ }): Promise<RunResult & {
125
+ workspace: string;
126
+ }>;
127
+ export {};
128
+ //# sourceMappingURL=provision.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provision.d.ts","sourceRoot":"","sources":["../src/provision.ts"],"names":[],"mappings":"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"}