@salte-common/terraflow 0.1.0-alpha.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.
- package/LICENSE +22 -0
- package/README.md +278 -0
- package/RELEASE_SUMMARY.md +53 -0
- package/STANDARDS_COMPLIANCE.md +85 -0
- package/bin/terraflow.js +3 -0
- package/bin/tf.js +3 -0
- package/dist/commands/apply.d.ts +7 -0
- package/dist/commands/apply.js +12 -0
- package/dist/commands/base.d.ts +7 -0
- package/dist/commands/base.js +12 -0
- package/dist/commands/config.d.ts +25 -0
- package/dist/commands/config.js +354 -0
- package/dist/commands/destroy.d.ts +7 -0
- package/dist/commands/destroy.js +12 -0
- package/dist/commands/init.d.ts +68 -0
- package/dist/commands/init.js +131 -0
- package/dist/commands/plan.d.ts +7 -0
- package/dist/commands/plan.js +12 -0
- package/dist/core/backend-state.d.ts +25 -0
- package/dist/core/backend-state.js +77 -0
- package/dist/core/config.d.ts +83 -0
- package/dist/core/config.js +295 -0
- package/dist/core/context.d.ts +52 -0
- package/dist/core/context.js +192 -0
- package/dist/core/environment.d.ts +62 -0
- package/dist/core/environment.js +205 -0
- package/dist/core/errors.d.ts +22 -0
- package/dist/core/errors.js +36 -0
- package/dist/core/plugin-loader.d.ts +21 -0
- package/dist/core/plugin-loader.js +136 -0
- package/dist/core/terraform.d.ts +45 -0
- package/dist/core/terraform.js +247 -0
- package/dist/core/validator.d.ts +103 -0
- package/dist/core/validator.js +304 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +184 -0
- package/dist/plugins/auth/aws-assume-role.d.ts +10 -0
- package/dist/plugins/auth/aws-assume-role.js +110 -0
- package/dist/plugins/auth/azure-service-principal.d.ts +10 -0
- package/dist/plugins/auth/azure-service-principal.js +99 -0
- package/dist/plugins/auth/gcp-service-account.d.ts +10 -0
- package/dist/plugins/auth/gcp-service-account.js +105 -0
- package/dist/plugins/backends/azurerm.d.ts +10 -0
- package/dist/plugins/backends/azurerm.js +117 -0
- package/dist/plugins/backends/gcs.d.ts +10 -0
- package/dist/plugins/backends/gcs.js +75 -0
- package/dist/plugins/backends/local.d.ts +11 -0
- package/dist/plugins/backends/local.js +37 -0
- package/dist/plugins/backends/s3.d.ts +10 -0
- package/dist/plugins/backends/s3.js +185 -0
- package/dist/plugins/secrets/aws-secrets.d.ts +12 -0
- package/dist/plugins/secrets/aws-secrets.js +125 -0
- package/dist/plugins/secrets/azure-keyvault.d.ts +12 -0
- package/dist/plugins/secrets/azure-keyvault.js +178 -0
- package/dist/plugins/secrets/env.d.ts +24 -0
- package/dist/plugins/secrets/env.js +62 -0
- package/dist/plugins/secrets/gcp-secret-manager.d.ts +12 -0
- package/dist/plugins/secrets/gcp-secret-manager.js +157 -0
- package/dist/templates/application/go/go.mod.template +4 -0
- package/dist/templates/application/go/main.template +8 -0
- package/dist/templates/application/go/test.template +11 -0
- package/dist/templates/application/javascript/main.template +14 -0
- package/dist/templates/application/javascript/test.template +8 -0
- package/dist/templates/application/python/main.template +13 -0
- package/dist/templates/application/python/requirements.txt.template +3 -0
- package/dist/templates/application/python/test.template +8 -0
- package/dist/templates/application/typescript/main.template +14 -0
- package/dist/templates/application/typescript/test.template +8 -0
- package/dist/templates/application/typescript/tsconfig.json.template +20 -0
- package/dist/templates/config/README.md.template +82 -0
- package/dist/templates/config/env.example.template +22 -0
- package/dist/templates/config/gitignore.template +40 -0
- package/dist/templates/config/tfwconfig.yml.template +69 -0
- package/dist/templates/templates/application/go/go.mod.template +4 -0
- package/dist/templates/templates/application/go/main.template +8 -0
- package/dist/templates/templates/application/go/test.template +11 -0
- package/dist/templates/templates/application/javascript/main.template +14 -0
- package/dist/templates/templates/application/javascript/test.template +8 -0
- package/dist/templates/templates/application/python/main.template +13 -0
- package/dist/templates/templates/application/python/requirements.txt.template +3 -0
- package/dist/templates/templates/application/python/test.template +8 -0
- package/dist/templates/templates/application/typescript/main.template +14 -0
- package/dist/templates/templates/application/typescript/test.template +8 -0
- package/dist/templates/templates/application/typescript/tsconfig.json.template +20 -0
- package/dist/templates/templates/config/README.md.template +82 -0
- package/dist/templates/templates/config/env.example.template +22 -0
- package/dist/templates/templates/config/gitignore.template +40 -0
- package/dist/templates/templates/config/tfwconfig.yml.template +69 -0
- package/dist/templates/templates/terraform/aws/_init.tf.template +24 -0
- package/dist/templates/templates/terraform/aws/inputs.tf.template +11 -0
- package/dist/templates/templates/terraform/azure/_init.tf.template +19 -0
- package/dist/templates/templates/terraform/azure/inputs.tf.template +11 -0
- package/dist/templates/templates/terraform/gcp/_init.tf.template +20 -0
- package/dist/templates/templates/terraform/gcp/inputs.tf.template +16 -0
- package/dist/templates/templates/terraform/locals.tf.template +9 -0
- package/dist/templates/templates/terraform/main.tf.template +8 -0
- package/dist/templates/templates/terraform/modules/inputs.tf.template +5 -0
- package/dist/templates/templates/terraform/modules/main.tf.template +2 -0
- package/dist/templates/templates/terraform/modules/outputs.tf.template +2 -0
- package/dist/templates/templates/terraform/outputs.tf.template +6 -0
- package/dist/templates/terraform/aws/_init.tf.template +24 -0
- package/dist/templates/terraform/aws/inputs.tf.template +11 -0
- package/dist/templates/terraform/azure/_init.tf.template +19 -0
- package/dist/templates/terraform/azure/inputs.tf.template +11 -0
- package/dist/templates/terraform/gcp/_init.tf.template +20 -0
- package/dist/templates/terraform/gcp/inputs.tf.template +16 -0
- package/dist/templates/terraform/locals.tf.template +9 -0
- package/dist/templates/terraform/main.tf.template +8 -0
- package/dist/templates/terraform/modules/inputs.tf.template +5 -0
- package/dist/templates/terraform/modules/main.tf.template +2 -0
- package/dist/templates/terraform/modules/outputs.tf.template +2 -0
- package/dist/templates/terraform/outputs.tf.template +6 -0
- package/dist/types/config.d.ts +92 -0
- package/dist/types/config.js +6 -0
- package/dist/types/context.d.ts +59 -0
- package/dist/types/context.js +6 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.js +23 -0
- package/dist/types/plugins.d.ts +77 -0
- package/dist/types/plugins.js +6 -0
- package/dist/utils/cloud.d.ts +43 -0
- package/dist/utils/cloud.js +150 -0
- package/dist/utils/git.d.ts +88 -0
- package/dist/utils/git.js +258 -0
- package/dist/utils/logger.d.ts +67 -0
- package/dist/utils/logger.js +121 -0
- package/dist/utils/scaffolding.d.ts +92 -0
- package/dist/utils/scaffolding.js +338 -0
- package/dist/utils/templates.d.ts +25 -0
- package/dist/utils/templates.js +70 -0
- package/package.json +60 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Environment secrets plugin
|
|
4
|
+
* No-op plugin for when users manage secrets via .env files
|
|
5
|
+
*
|
|
6
|
+
* This plugin does not fetch secrets from an external service.
|
|
7
|
+
* Instead, it allows users to manage TF_VAR_* environment variables
|
|
8
|
+
* directly in their .env file or existing environment variables.
|
|
9
|
+
*
|
|
10
|
+
* The .env file is loaded by EnvironmentSetup.loadEnvFile() which
|
|
11
|
+
* does NOT automatically convert variables to TF_VAR_* prefix.
|
|
12
|
+
* Users must manage the TF_VAR_* prefix themselves in .env files.
|
|
13
|
+
*
|
|
14
|
+
* This plugin returns an empty object because:
|
|
15
|
+
* - Secrets come from .env file (loaded separately)
|
|
16
|
+
* - Secrets come from existing environment variables (already available)
|
|
17
|
+
* - No automatic conversion or fetching is performed
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.envSecrets = void 0;
|
|
21
|
+
/**
|
|
22
|
+
* Environment secrets plugin
|
|
23
|
+
* Default and simplest secrets provider - no-op
|
|
24
|
+
*/
|
|
25
|
+
exports.envSecrets = {
|
|
26
|
+
name: 'env',
|
|
27
|
+
/**
|
|
28
|
+
* Validate secrets configuration
|
|
29
|
+
* Always succeeds - no configuration required for env plugin
|
|
30
|
+
* @param _config - Secrets configuration (ignored)
|
|
31
|
+
*/
|
|
32
|
+
validate: async (_config) => {
|
|
33
|
+
// No validation needed - env plugin is always valid
|
|
34
|
+
// Users manage secrets directly in .env file or environment variables
|
|
35
|
+
return Promise.resolve();
|
|
36
|
+
},
|
|
37
|
+
/**
|
|
38
|
+
* Retrieve secrets
|
|
39
|
+
* Returns empty object because secrets come from .env file or existing env vars
|
|
40
|
+
*
|
|
41
|
+
* This plugin does NOT:
|
|
42
|
+
* - Fetch secrets from external services
|
|
43
|
+
* - Convert environment variables to TF_VAR_* prefix
|
|
44
|
+
* - Load .env files (handled by EnvironmentSetup.loadEnvFile())
|
|
45
|
+
*
|
|
46
|
+
* Users must:
|
|
47
|
+
* - Manage TF_VAR_* prefix themselves in .env files
|
|
48
|
+
* - Set environment variables with TF_VAR_* prefix directly
|
|
49
|
+
* - Or use config.variables section for automatic conversion
|
|
50
|
+
*
|
|
51
|
+
* @param _config - Secrets configuration (ignored)
|
|
52
|
+
* @param _context - Execution context (ignored)
|
|
53
|
+
* @returns Empty object - secrets come from .env or existing env vars
|
|
54
|
+
*/
|
|
55
|
+
getSecrets: async (_config, _context) => {
|
|
56
|
+
// Return empty object - secrets are already in environment
|
|
57
|
+
// .env file is loaded separately by EnvironmentSetup.loadEnvFile()
|
|
58
|
+
// Existing TF_VAR_* environment variables pass through unchanged
|
|
59
|
+
return {};
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GCP Secret Manager plugin
|
|
3
|
+
* Retrieves secrets from GCP Secret Manager and converts them to TF_VAR_* environment variables
|
|
4
|
+
*
|
|
5
|
+
* CONVENTION: Every key in the secret automatically becomes TF_VAR_{key}
|
|
6
|
+
*/
|
|
7
|
+
import type { SecretsPlugin } from '../../types';
|
|
8
|
+
/**
|
|
9
|
+
* GCP Secret Manager secrets plugin
|
|
10
|
+
*/
|
|
11
|
+
export declare const gcpSecretManager: SecretsPlugin;
|
|
12
|
+
//# sourceMappingURL=gcp-secret-manager.d.ts.map
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* GCP Secret Manager plugin
|
|
4
|
+
* Retrieves secrets from GCP Secret Manager and converts them to TF_VAR_* environment variables
|
|
5
|
+
*
|
|
6
|
+
* CONVENTION: Every key in the secret automatically becomes TF_VAR_{key}
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.gcpSecretManager = void 0;
|
|
10
|
+
const child_process_1 = require("child_process");
|
|
11
|
+
const errors_1 = require("../../core/errors");
|
|
12
|
+
const logger_1 = require("../../utils/logger");
|
|
13
|
+
/**
|
|
14
|
+
* Process secret value and convert to TF_VAR_* format
|
|
15
|
+
*/
|
|
16
|
+
function processSecretValue(secretName, secretValue) {
|
|
17
|
+
// Try to parse as JSON
|
|
18
|
+
let secretData;
|
|
19
|
+
try {
|
|
20
|
+
const parsed = JSON.parse(secretValue);
|
|
21
|
+
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
|
|
22
|
+
secretData = parsed;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
// Not a JSON object, treat the entire secret value as a single key
|
|
26
|
+
secretData = { [secretName]: secretValue };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Not valid JSON, treat the entire secret value as a single key
|
|
31
|
+
secretData = { [secretName]: secretValue };
|
|
32
|
+
}
|
|
33
|
+
// Convert all keys to TF_VAR_{key} format
|
|
34
|
+
const tfVars = {};
|
|
35
|
+
for (const key in secretData) {
|
|
36
|
+
if (Object.prototype.hasOwnProperty.call(secretData, key)) {
|
|
37
|
+
const value = secretData[key];
|
|
38
|
+
const tfVarKey = `TF_VAR_${key}`;
|
|
39
|
+
// Convert value to string
|
|
40
|
+
if (value === null || value === undefined) {
|
|
41
|
+
tfVars[tfVarKey] = '';
|
|
42
|
+
}
|
|
43
|
+
else if (typeof value === 'string') {
|
|
44
|
+
tfVars[tfVarKey] = value;
|
|
45
|
+
}
|
|
46
|
+
else if (typeof value === 'number' || typeof value === 'boolean') {
|
|
47
|
+
tfVars[tfVarKey] = String(value);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// For objects/arrays, convert to JSON string
|
|
51
|
+
tfVars[tfVarKey] = JSON.stringify(value);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
logger_1.Logger.info(`✅ Loaded ${Object.keys(tfVars).length} Terraform variables from GCP Secret Manager`);
|
|
56
|
+
return tfVars;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* GCP Secret Manager secrets plugin
|
|
60
|
+
*/
|
|
61
|
+
exports.gcpSecretManager = {
|
|
62
|
+
name: 'gcp-secret-manager',
|
|
63
|
+
/**
|
|
64
|
+
* Validate GCP Secret Manager configuration
|
|
65
|
+
* @param config - Secrets configuration
|
|
66
|
+
* @throws {ConfigError} If configuration is invalid
|
|
67
|
+
*/
|
|
68
|
+
validate: async (config) => {
|
|
69
|
+
if (!config.config) {
|
|
70
|
+
throw new errors_1.ConfigError('GCP Secret Manager requires configuration');
|
|
71
|
+
}
|
|
72
|
+
const gcpConfig = config.config;
|
|
73
|
+
// secret_name is required
|
|
74
|
+
if (!gcpConfig.secret_name) {
|
|
75
|
+
throw new errors_1.ConfigError('GCP Secret Manager requires "secret_name" configuration');
|
|
76
|
+
}
|
|
77
|
+
// project_id should be set (from config, context, or GCLOUD_PROJECT env)
|
|
78
|
+
const projectId = gcpConfig.project_id ||
|
|
79
|
+
process.env.GCLOUD_PROJECT ||
|
|
80
|
+
process.env.GCP_PROJECT ||
|
|
81
|
+
process.env.GOOGLE_CLOUD_PROJECT;
|
|
82
|
+
if (!projectId && !process.env.GOOGLE_APPLICATION_CREDENTIALS) {
|
|
83
|
+
// Warning but not error - GCP SDK can detect project from credentials
|
|
84
|
+
logger_1.Logger.debug('GCP project_id not specified, will attempt to auto-detect from credentials');
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
/**
|
|
88
|
+
* Retrieve secrets from GCP Secret Manager
|
|
89
|
+
* All keys are automatically prefixed with TF_VAR_
|
|
90
|
+
* @param config - Secrets configuration
|
|
91
|
+
* @param context - Execution context
|
|
92
|
+
* @returns Record of environment variable key-value pairs (prefixed with TF_VAR_)
|
|
93
|
+
*/
|
|
94
|
+
getSecrets: async (config, context) => {
|
|
95
|
+
if (!config.config) {
|
|
96
|
+
throw new errors_1.ConfigError('GCP Secret Manager requires configuration');
|
|
97
|
+
}
|
|
98
|
+
const gcpConfig = config.config;
|
|
99
|
+
const secretName = gcpConfig.secret_name;
|
|
100
|
+
try {
|
|
101
|
+
// Determine project ID: config > context > env
|
|
102
|
+
let projectId = gcpConfig.project_id ||
|
|
103
|
+
context.cloud.gcpProjectId ||
|
|
104
|
+
process.env.GCLOUD_PROJECT ||
|
|
105
|
+
process.env.GCP_PROJECT ||
|
|
106
|
+
process.env.GOOGLE_CLOUD_PROJECT;
|
|
107
|
+
if (!projectId) {
|
|
108
|
+
// Try to get project ID from gcloud config
|
|
109
|
+
try {
|
|
110
|
+
const detectedProjectId = (0, child_process_1.execSync)('gcloud config get-value project', {
|
|
111
|
+
encoding: 'utf8',
|
|
112
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
113
|
+
}).trim();
|
|
114
|
+
if (detectedProjectId) {
|
|
115
|
+
logger_1.Logger.debug(`Detected GCP project ID: ${detectedProjectId}`);
|
|
116
|
+
projectId = detectedProjectId;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// Continue to error
|
|
121
|
+
}
|
|
122
|
+
if (!projectId) {
|
|
123
|
+
throw new errors_1.ConfigError('GCP project_id is required. Set it in config, GCLOUD_PROJECT environment variable, or run "gcloud config set project PROJECT_ID".');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
logger_1.Logger.debug(`Fetching secret "${secretName}" from GCP Secret Manager (project: ${projectId})`);
|
|
127
|
+
// Fetch secret using gcloud CLI
|
|
128
|
+
const result = (0, child_process_1.execSync)(`gcloud secrets versions access latest --secret="${secretName}" --project="${projectId}"`, {
|
|
129
|
+
encoding: 'utf8',
|
|
130
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
131
|
+
});
|
|
132
|
+
const secretValue = result.trim();
|
|
133
|
+
return processSecretValue(secretName, secretValue);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
if (error instanceof errors_1.ConfigError) {
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
139
|
+
// Handle specific GCP CLI errors
|
|
140
|
+
if (error instanceof Error) {
|
|
141
|
+
const errorMessage = error.message;
|
|
142
|
+
if (errorMessage.includes('PERMISSION_DENIED') || errorMessage.includes('403')) {
|
|
143
|
+
throw new errors_1.ConfigError(`Access denied when fetching secret "${secretName}". Ensure your GCP credentials have permission to access this secret.`);
|
|
144
|
+
}
|
|
145
|
+
if (errorMessage.includes('NOT_FOUND') || errorMessage.includes('404')) {
|
|
146
|
+
throw new errors_1.ConfigError(`Secret "${secretName}" not found in GCP Secret Manager.`);
|
|
147
|
+
}
|
|
148
|
+
if (errorMessage.includes('UNAUTHENTICATED') || errorMessage.includes('401')) {
|
|
149
|
+
throw new errors_1.ConfigError(`Authentication failed when accessing GCP Secret Manager. Ensure you have logged in with 'gcloud auth login' and have valid credentials.`);
|
|
150
|
+
}
|
|
151
|
+
throw new errors_1.ConfigError(`Failed to fetch secret "${secretName}" from GCP Secret Manager: ${errorMessage}. Ensure gcloud CLI is installed, you are logged in with 'gcloud auth login', and have valid permissions.`);
|
|
152
|
+
}
|
|
153
|
+
throw new errors_1.ConfigError(`Failed to fetch secret "${secretName}": ${String(error)}`);
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
//# sourceMappingURL=gcp-secret-manager.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2020"],
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*"],
|
|
18
|
+
"exclude": ["node_modules", "dist"]
|
|
19
|
+
}
|
|
20
|
+
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# <project-name>
|
|
2
|
+
|
|
3
|
+
Infrastructure as Code project managed with [Terraflow](https://github.com/salte-common/terraflow).
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- [Terraform](https://www.terraform.io/downloads) >= 1.0
|
|
8
|
+
- [Node.js](https://nodejs.org/) >= 18.x
|
|
9
|
+
- [Terraflow](https://www.npmjs.com/package/terraflow): `npm install -g terraflow`
|
|
10
|
+
- Cloud provider credentials (<provider>)
|
|
11
|
+
|
|
12
|
+
## Getting Started
|
|
13
|
+
|
|
14
|
+
1. Copy `.env.example` to `.env` and configure your credentials:
|
|
15
|
+
```bash
|
|
16
|
+
cp .env.example .env
|
|
17
|
+
# Edit .env with your credentials
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
2. Review and update `.tfwconfig.yml` with your backend configuration
|
|
21
|
+
|
|
22
|
+
3. Initialize Terraform:
|
|
23
|
+
```bash
|
|
24
|
+
terraflow init
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
4. Plan your infrastructure:
|
|
28
|
+
```bash
|
|
29
|
+
terraflow plan
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
5. Apply your infrastructure:
|
|
33
|
+
```bash
|
|
34
|
+
terraflow apply
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Project Structure
|
|
38
|
+
|
|
39
|
+
- `src/` - Application source code
|
|
40
|
+
- `main/` - Main application code
|
|
41
|
+
- `test/` - Test files
|
|
42
|
+
- `terraform/` - Infrastructure as Code
|
|
43
|
+
- `modules/` - Reusable Terraform modules
|
|
44
|
+
- `_init.tf` - Provider and backend configuration
|
|
45
|
+
- `*.tf` - Main terraform configuration
|
|
46
|
+
- `.tfwconfig.yml` - Terraflow configuration
|
|
47
|
+
- `.env` - Local environment variables (not committed)
|
|
48
|
+
|
|
49
|
+
## Terraflow Commands
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Initialize terraform and workspace
|
|
53
|
+
terraflow init
|
|
54
|
+
|
|
55
|
+
# Plan changes
|
|
56
|
+
terraflow plan
|
|
57
|
+
|
|
58
|
+
# Apply changes
|
|
59
|
+
terraflow apply
|
|
60
|
+
|
|
61
|
+
# Destroy infrastructure
|
|
62
|
+
terraflow destroy
|
|
63
|
+
|
|
64
|
+
# Show current configuration
|
|
65
|
+
terraflow config show
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Workspace Management
|
|
69
|
+
|
|
70
|
+
Terraflow automatically derives workspace names from your git branch:
|
|
71
|
+
- Main branch → `main` workspace
|
|
72
|
+
- Feature branches (e.g., `feature/new-api`) → hostname-based workspace
|
|
73
|
+
- Can be overridden with `--workspace` flag
|
|
74
|
+
|
|
75
|
+
## Configuration
|
|
76
|
+
|
|
77
|
+
See `.tfwconfig.yml` for all available options and the [documentation](https://github.com/salte-common/terraflow/blob/main/docs/configuration.md) for detailed configuration reference.
|
|
78
|
+
|
|
79
|
+
## License
|
|
80
|
+
|
|
81
|
+
MIT
|
|
82
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# AWS Credentials (for S3 backend and AWS provider)
|
|
2
|
+
# AWS_ACCESS_KEY_ID=your_access_key
|
|
3
|
+
# AWS_SECRET_ACCESS_KEY=your_secret_key
|
|
4
|
+
# AWS_REGION=us-east-1
|
|
5
|
+
|
|
6
|
+
# Azure Credentials (for Azure backend and provider)
|
|
7
|
+
# ARM_CLIENT_ID=your_client_id
|
|
8
|
+
# ARM_CLIENT_SECRET=your_client_secret
|
|
9
|
+
# ARM_SUBSCRIPTION_ID=your_subscription_id
|
|
10
|
+
# ARM_TENANT_ID=your_tenant_id
|
|
11
|
+
|
|
12
|
+
# GCP Credentials (for GCS backend and GCP provider)
|
|
13
|
+
# GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json
|
|
14
|
+
# GCP_PROJECT_ID=your-project-id
|
|
15
|
+
|
|
16
|
+
# Terraflow Configuration
|
|
17
|
+
# TERRAFLOW_WORKSPACE=development
|
|
18
|
+
# TERRAFLOW_SKIP_COMMIT_CHECK=false
|
|
19
|
+
|
|
20
|
+
# Terraform Variables (TF_VAR_*)
|
|
21
|
+
# TF_VAR_environment=development
|
|
22
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Terraform
|
|
2
|
+
**/.terraform/*
|
|
3
|
+
*.tfstate
|
|
4
|
+
*.tfstate.*
|
|
5
|
+
*.tfvars
|
|
6
|
+
.terraform.lock.hcl
|
|
7
|
+
|
|
8
|
+
# Terraflow
|
|
9
|
+
.terraflow/
|
|
10
|
+
|
|
11
|
+
# Environment
|
|
12
|
+
.env
|
|
13
|
+
|
|
14
|
+
# Language-specific (adjust based on --language)
|
|
15
|
+
# Node.js:
|
|
16
|
+
node_modules/
|
|
17
|
+
npm-debug.log*
|
|
18
|
+
dist/
|
|
19
|
+
|
|
20
|
+
# Python:
|
|
21
|
+
__pycache__/
|
|
22
|
+
*.py[cod]
|
|
23
|
+
venv/
|
|
24
|
+
.pytest_cache/
|
|
25
|
+
*.egg-info/
|
|
26
|
+
|
|
27
|
+
# Go:
|
|
28
|
+
*.exe
|
|
29
|
+
*.dll
|
|
30
|
+
*.so
|
|
31
|
+
*.dylib
|
|
32
|
+
vendor/
|
|
33
|
+
|
|
34
|
+
# IDE
|
|
35
|
+
.vscode/
|
|
36
|
+
.idea/
|
|
37
|
+
*.swp
|
|
38
|
+
*.swo
|
|
39
|
+
.DS_Store
|
|
40
|
+
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Terraflow configuration
|
|
2
|
+
# See: https://github.com/salte-common/terraflow/blob/main/docs/configuration.md
|
|
3
|
+
|
|
4
|
+
# Working directory for terraform files
|
|
5
|
+
working-dir: ./terraform
|
|
6
|
+
|
|
7
|
+
# Workspace derivation strategy
|
|
8
|
+
workspace_strategy:
|
|
9
|
+
- cli
|
|
10
|
+
- env
|
|
11
|
+
- tag
|
|
12
|
+
- branch
|
|
13
|
+
- hostname
|
|
14
|
+
|
|
15
|
+
# Backend configuration (adjust for your provider)
|
|
16
|
+
backend:
|
|
17
|
+
type: <provider> # local, s3, azurerm, or gcs
|
|
18
|
+
config:
|
|
19
|
+
# Template variables are supported: ${VAR_NAME}
|
|
20
|
+
# See documentation for available template variables
|
|
21
|
+
|
|
22
|
+
# Uncomment and configure based on your provider:
|
|
23
|
+
|
|
24
|
+
# AWS S3 Backend:
|
|
25
|
+
# bucket: ${AWS_REGION}-${AWS_ACCOUNT_ID}-terraform-state
|
|
26
|
+
# key: ${GITHUB_REPOSITORY}
|
|
27
|
+
# region: ${AWS_REGION}
|
|
28
|
+
# dynamodb_table: terraform-statelock
|
|
29
|
+
# encrypt: true
|
|
30
|
+
|
|
31
|
+
# Azure Backend:
|
|
32
|
+
# storage_account_name: mystorageaccount
|
|
33
|
+
# container_name: tfstate
|
|
34
|
+
# key: terraform.tfstate
|
|
35
|
+
|
|
36
|
+
# GCP Backend:
|
|
37
|
+
# bucket: my-gcs-bucket
|
|
38
|
+
# prefix: terraform/state
|
|
39
|
+
|
|
40
|
+
# Uncomment to configure secrets from secret manager
|
|
41
|
+
# secrets:
|
|
42
|
+
# provider: env # env | aws-secrets | azure-keyvault | gcp-secret-manager
|
|
43
|
+
# config:
|
|
44
|
+
# # AWS Secrets Manager:
|
|
45
|
+
# # region: us-east-1
|
|
46
|
+
# # secret_name: <project-name>/terraform-vars
|
|
47
|
+
#
|
|
48
|
+
# # Azure Key Vault:
|
|
49
|
+
# # vault_name: my-keyvault
|
|
50
|
+
#
|
|
51
|
+
# # GCP Secret Manager:
|
|
52
|
+
# # project_id: my-project
|
|
53
|
+
|
|
54
|
+
# Terraform variables
|
|
55
|
+
variables:
|
|
56
|
+
environment: development
|
|
57
|
+
|
|
58
|
+
# Validations
|
|
59
|
+
validations:
|
|
60
|
+
require_git_commit: true
|
|
61
|
+
# allowed_workspaces:
|
|
62
|
+
# - development
|
|
63
|
+
# - staging
|
|
64
|
+
# - production
|
|
65
|
+
|
|
66
|
+
# Logging
|
|
67
|
+
logging:
|
|
68
|
+
level: info
|
|
69
|
+
|