spaceforge 1.1.3__tar.gz → 1.1.4__tar.gz
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.
- {spaceforge-1.1.3 → spaceforge-1.1.4}/PKG-INFO +13 -13
- {spaceforge-1.1.3 → spaceforge-1.1.4}/README.md +12 -12
- {spaceforge-1.1.3 → spaceforge-1.1.4}/plugins/enviroment_manager/plugin.py +5 -5
- {spaceforge-1.1.3 → spaceforge-1.1.4}/plugins/enviroment_manager/plugin.yaml +11 -11
- {spaceforge-1.1.3 → spaceforge-1.1.4}/plugins/sops/plugin.yaml +1 -1
- spaceforge-1.1.4/plugins/tflint/plugin.py +195 -0
- spaceforge-1.1.4/plugins/tflint/plugin.yaml +363 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/plugins/wiz/plugin.yaml +1 -1
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/README.md +5 -5
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/__main__.py +13 -2
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/_version_scm.py +3 -3
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/runner.py +2 -2
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/templates/ensure_spaceforge_and_run.sh.j2 +1 -1
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/test_generator.py +1 -2
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/test_runner.py +5 -6
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/test_runner_cli.py +3 -3
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge.egg-info/PKG-INFO +13 -13
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge.egg-info/SOURCES.txt +2 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/.github/workflows/ci.yml +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/.github/workflows/release.yml +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/.gitignore +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/LICENSE +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/MANIFEST.in +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/go.mod +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/plugins/enviroment_manager/requirements.txt +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/plugins/envsubst/plugin.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/plugins/envsubst/plugin.yaml +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/plugins/infracost/plugin.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/plugins/infracost/plugin.yaml +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/plugins/sops/plugin.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/plugins/sops/requirements.txt +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/plugins/wiz/plugin.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/pyproject.toml +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/setup.cfg +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/setup.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/__init__.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/_version.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/cls.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/conftest.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/generator.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/plugin.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/schema.json +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/templates/binary_install.sh.j2 +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/test_cls.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/test_generator_binaries.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/test_generator_core.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/test_generator_hooks.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/test_generator_parameters.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/test_plugin.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/test_plugin_file_operations.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/test_plugin_hooks.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/test_plugin_inheritance.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/test_runner_core.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge/test_runner_execution.py +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge.egg-info/dependency_links.txt +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge.egg-info/entry_points.txt +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge.egg-info/not-zip-safe +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge.egg-info/requires.txt +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/spaceforge.egg-info/top_level.txt +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/templates.go +0 -0
- {spaceforge-1.1.3 → spaceforge-1.1.4}/test.sh +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spaceforge
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.4
|
|
4
4
|
Summary: A Python framework for building Spacelift plugins
|
|
5
5
|
Home-page: https://github.com/spacelift-io/plugins
|
|
6
6
|
Author: Spacelift
|
|
@@ -60,15 +60,15 @@ pip install spaceforge
|
|
|
60
60
|
|
|
61
61
|
### 1. Create Your Plugin
|
|
62
62
|
|
|
63
|
-
Create a Python file (e.g., `
|
|
63
|
+
Create a Python file (e.g., `plugin.py`) and inherit from `SpaceforgePlugin`:
|
|
64
64
|
|
|
65
65
|
```python
|
|
66
|
-
from spaceforge import SpaceforgePlugin, Parameter, Variable, Context
|
|
66
|
+
from spaceforge import SpaceforgePlugin, Parameter, Variable, Context
|
|
67
67
|
import os
|
|
68
68
|
|
|
69
69
|
class MyPlugin(SpaceforgePlugin):
|
|
70
70
|
# Plugin metadata
|
|
71
|
-
__plugin_name__ = "my-
|
|
71
|
+
__plugin_name__ = "my-plugin"
|
|
72
72
|
__version__ = "1.0.0"
|
|
73
73
|
__author__ = "Your Name"
|
|
74
74
|
__labels__ = ["security", "monitoring"] # Optional labels for categorization
|
|
@@ -127,7 +127,7 @@ class MyPlugin(SpaceforgePlugin):
|
|
|
127
127
|
Generate the Spacelift plugin YAML manifest:
|
|
128
128
|
|
|
129
129
|
```bash
|
|
130
|
-
spaceforge generate
|
|
130
|
+
spaceforge generate plugin.py
|
|
131
131
|
```
|
|
132
132
|
|
|
133
133
|
This creates `plugin.yaml` that you can upload to Spacelift.
|
|
@@ -142,7 +142,7 @@ export API_KEY="your-api-key"
|
|
|
142
142
|
export ENVIRONMENT="staging"
|
|
143
143
|
|
|
144
144
|
# Test the after_plan hook
|
|
145
|
-
spaceforge
|
|
145
|
+
spaceforge run after_plan
|
|
146
146
|
```
|
|
147
147
|
|
|
148
148
|
## Available Hooks
|
|
@@ -527,13 +527,13 @@ export API_KEY="test-key"
|
|
|
527
527
|
export TIMEOUT="60"
|
|
528
528
|
|
|
529
529
|
# Test specific hook
|
|
530
|
-
spaceforge
|
|
530
|
+
spaceforge run after_plan
|
|
531
531
|
|
|
532
532
|
# Test with specific plugin file
|
|
533
|
-
spaceforge
|
|
533
|
+
spaceforge run --plugin-file my_plugin.py before_apply
|
|
534
534
|
|
|
535
535
|
# Get help
|
|
536
|
-
spaceforge
|
|
536
|
+
spaceforge run --help
|
|
537
537
|
```
|
|
538
538
|
|
|
539
539
|
## Plugin Development Tips
|
|
@@ -577,7 +577,7 @@ def after_plan(self):
|
|
|
577
577
|
### 4. Testing and Debugging
|
|
578
578
|
|
|
579
579
|
- Set `SPACELIFT_DEBUG=true` to enable debug logging
|
|
580
|
-
- Use the
|
|
580
|
+
- Use the `run` command to test hooks during development
|
|
581
581
|
- Test with different parameter combinations
|
|
582
582
|
- Validate your generated YAML before uploading to Spacelift
|
|
583
583
|
|
|
@@ -718,7 +718,7 @@ spaceforge generate security_scanner.py
|
|
|
718
718
|
# Test locally
|
|
719
719
|
export API_TOKEN="your-token"
|
|
720
720
|
export SEVERITY_THRESHOLD="high"
|
|
721
|
-
spaceforge
|
|
721
|
+
spaceforge run after_plan
|
|
722
722
|
```
|
|
723
723
|
|
|
724
724
|
## Speeding up plugin execution
|
|
@@ -734,8 +734,8 @@ There are a few things you can do to speed up plugin execution.
|
|
|
734
734
|
|
|
735
735
|
1. **Install spaceforge:** `pip install spaceforge`
|
|
736
736
|
2. **Create your plugin:** Start with the quick start example
|
|
737
|
-
3. **Test locally:** Use the
|
|
738
|
-
4. **Generate manifest:** Use the generate command to create plugin.yaml
|
|
737
|
+
3. **Test locally:** Use the `run` command to test your hooks
|
|
738
|
+
4. **Generate manifest:** Use the `generate` command to create plugin.yaml
|
|
739
739
|
5. **Upload to Spacelift:** Add your plugin manifest to your Spacelift account
|
|
740
740
|
|
|
741
741
|
For more advanced examples, see the [plugins](plugins/) directory in this repository.
|
|
@@ -14,15 +14,15 @@ pip install spaceforge
|
|
|
14
14
|
|
|
15
15
|
### 1. Create Your Plugin
|
|
16
16
|
|
|
17
|
-
Create a Python file (e.g., `
|
|
17
|
+
Create a Python file (e.g., `plugin.py`) and inherit from `SpaceforgePlugin`:
|
|
18
18
|
|
|
19
19
|
```python
|
|
20
|
-
from spaceforge import SpaceforgePlugin, Parameter, Variable, Context
|
|
20
|
+
from spaceforge import SpaceforgePlugin, Parameter, Variable, Context
|
|
21
21
|
import os
|
|
22
22
|
|
|
23
23
|
class MyPlugin(SpaceforgePlugin):
|
|
24
24
|
# Plugin metadata
|
|
25
|
-
__plugin_name__ = "my-
|
|
25
|
+
__plugin_name__ = "my-plugin"
|
|
26
26
|
__version__ = "1.0.0"
|
|
27
27
|
__author__ = "Your Name"
|
|
28
28
|
__labels__ = ["security", "monitoring"] # Optional labels for categorization
|
|
@@ -81,7 +81,7 @@ class MyPlugin(SpaceforgePlugin):
|
|
|
81
81
|
Generate the Spacelift plugin YAML manifest:
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
|
-
spaceforge generate
|
|
84
|
+
spaceforge generate plugin.py
|
|
85
85
|
```
|
|
86
86
|
|
|
87
87
|
This creates `plugin.yaml` that you can upload to Spacelift.
|
|
@@ -96,7 +96,7 @@ export API_KEY="your-api-key"
|
|
|
96
96
|
export ENVIRONMENT="staging"
|
|
97
97
|
|
|
98
98
|
# Test the after_plan hook
|
|
99
|
-
spaceforge
|
|
99
|
+
spaceforge run after_plan
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
## Available Hooks
|
|
@@ -481,13 +481,13 @@ export API_KEY="test-key"
|
|
|
481
481
|
export TIMEOUT="60"
|
|
482
482
|
|
|
483
483
|
# Test specific hook
|
|
484
|
-
spaceforge
|
|
484
|
+
spaceforge run after_plan
|
|
485
485
|
|
|
486
486
|
# Test with specific plugin file
|
|
487
|
-
spaceforge
|
|
487
|
+
spaceforge run --plugin-file my_plugin.py before_apply
|
|
488
488
|
|
|
489
489
|
# Get help
|
|
490
|
-
spaceforge
|
|
490
|
+
spaceforge run --help
|
|
491
491
|
```
|
|
492
492
|
|
|
493
493
|
## Plugin Development Tips
|
|
@@ -531,7 +531,7 @@ def after_plan(self):
|
|
|
531
531
|
### 4. Testing and Debugging
|
|
532
532
|
|
|
533
533
|
- Set `SPACELIFT_DEBUG=true` to enable debug logging
|
|
534
|
-
- Use the
|
|
534
|
+
- Use the `run` command to test hooks during development
|
|
535
535
|
- Test with different parameter combinations
|
|
536
536
|
- Validate your generated YAML before uploading to Spacelift
|
|
537
537
|
|
|
@@ -672,7 +672,7 @@ spaceforge generate security_scanner.py
|
|
|
672
672
|
# Test locally
|
|
673
673
|
export API_TOKEN="your-token"
|
|
674
674
|
export SEVERITY_THRESHOLD="high"
|
|
675
|
-
spaceforge
|
|
675
|
+
spaceforge run after_plan
|
|
676
676
|
```
|
|
677
677
|
|
|
678
678
|
## Speeding up plugin execution
|
|
@@ -688,8 +688,8 @@ There are a few things you can do to speed up plugin execution.
|
|
|
688
688
|
|
|
689
689
|
1. **Install spaceforge:** `pip install spaceforge`
|
|
690
690
|
2. **Create your plugin:** Start with the quick start example
|
|
691
|
-
3. **Test locally:** Use the
|
|
692
|
-
4. **Generate manifest:** Use the generate command to create plugin.yaml
|
|
691
|
+
3. **Test locally:** Use the `run` command to test your hooks
|
|
692
|
+
4. **Generate manifest:** Use the `generate` command to create plugin.yaml
|
|
693
693
|
5. **Upload to Spacelift:** Add your plugin manifest to your Spacelift account
|
|
694
694
|
|
|
695
695
|
For more advanced examples, see the [plugins](plugins/) directory in this repository.
|
|
@@ -109,15 +109,15 @@ The above configuration will create the following in a plan:
|
|
|
109
109
|
|
|
110
110
|
__parameters__ = [
|
|
111
111
|
Parameter(
|
|
112
|
-
name="Spacelift API
|
|
112
|
+
name="Spacelift API key ID",
|
|
113
113
|
id="spacelift_api_key_id",
|
|
114
|
-
description="The API
|
|
114
|
+
description="The API key that will trigger the stack previews",
|
|
115
115
|
required=True,
|
|
116
116
|
),
|
|
117
117
|
Parameter(
|
|
118
|
-
name="Spacelift API
|
|
118
|
+
name="Spacelift API key secret",
|
|
119
119
|
id="spacelift_api_key_secret",
|
|
120
|
-
description="The API
|
|
120
|
+
description="The API key secret that will trigger the stack previews",
|
|
121
121
|
required=True,
|
|
122
122
|
sensitive=True
|
|
123
123
|
),
|
|
@@ -126,7 +126,7 @@ The above configuration will create the following in a plan:
|
|
|
126
126
|
__contexts__ = [
|
|
127
127
|
Context(
|
|
128
128
|
name_prefix="Environment Manager",
|
|
129
|
-
description="Environment Manager
|
|
129
|
+
description="Environment Manager plugin",
|
|
130
130
|
hooks = {
|
|
131
131
|
"before_init": [
|
|
132
132
|
"mv /mnt/workspace/__environment_manager.tf /mnt/workspace/source/$TF_VAR_spacelift_project_root/__environment_manager.tf",
|
|
@@ -100,19 +100,19 @@ labels:
|
|
|
100
100
|
- management
|
|
101
101
|
- infrastructure
|
|
102
102
|
parameters:
|
|
103
|
-
- name: Spacelift API
|
|
104
|
-
description: The API
|
|
103
|
+
- name: Spacelift API key ID
|
|
104
|
+
description: The API key that will trigger the stack previews
|
|
105
105
|
sensitive: false
|
|
106
106
|
required: true
|
|
107
107
|
id: spacelift_api_key_id
|
|
108
|
-
- name: Spacelift API
|
|
109
|
-
description: The API
|
|
108
|
+
- name: Spacelift API key secret
|
|
109
|
+
description: The API key secret that will trigger the stack previews
|
|
110
110
|
sensitive: true
|
|
111
111
|
required: true
|
|
112
112
|
id: spacelift_api_key_secret
|
|
113
113
|
contexts:
|
|
114
114
|
- name_prefix: Environment Manager
|
|
115
|
-
description: Environment Manager
|
|
115
|
+
description: Environment Manager plugin
|
|
116
116
|
env:
|
|
117
117
|
- key: SPACELIFT_API_KEY_ID
|
|
118
118
|
value_from_parameter: spacelift_api_key_id
|
|
@@ -263,15 +263,15 @@ contexts:
|
|
|
263
263
|
|
|
264
264
|
__parameters__ = [
|
|
265
265
|
Parameter(
|
|
266
|
-
name="Spacelift API
|
|
266
|
+
name="Spacelift API key ID",
|
|
267
267
|
id="spacelift_api_key_id",
|
|
268
|
-
description="The API
|
|
268
|
+
description="The API key that will trigger the stack previews",
|
|
269
269
|
required=True,
|
|
270
270
|
),
|
|
271
271
|
Parameter(
|
|
272
|
-
name="Spacelift API
|
|
272
|
+
name="Spacelift API key secret",
|
|
273
273
|
id="spacelift_api_key_secret",
|
|
274
|
-
description="The API
|
|
274
|
+
description="The API key secret that will trigger the stack previews",
|
|
275
275
|
required=True,
|
|
276
276
|
sensitive=True
|
|
277
277
|
),
|
|
@@ -280,7 +280,7 @@ contexts:
|
|
|
280
280
|
__contexts__ = [
|
|
281
281
|
Context(
|
|
282
282
|
name_prefix="Environment Manager",
|
|
283
|
-
description="Environment Manager
|
|
283
|
+
description="Environment Manager plugin",
|
|
284
284
|
hooks = {
|
|
285
285
|
"before_init": [
|
|
286
286
|
"mv /mnt/workspace/__environment_manager.tf /mnt/workspace/source/$TF_VAR_spacelift_project_root/__environment_manager.tf",
|
|
@@ -458,7 +458,7 @@ contexts:
|
|
|
458
458
|
fi
|
|
459
459
|
|
|
460
460
|
cd /mnt/workspace/source/$TF_VAR_spacelift_project_root
|
|
461
|
-
spaceforge
|
|
461
|
+
spaceforge run --plugin-file /mnt/workspace/plugins/environment_manager/plugin.py before_init
|
|
462
462
|
sensitive: false
|
|
463
463
|
hooks:
|
|
464
464
|
before_init:
|
|
@@ -181,7 +181,7 @@ contexts:
|
|
|
181
181
|
export PATH="/mnt/workspace/plugins/plugin_binaries:$PATH"
|
|
182
182
|
|
|
183
183
|
cd /mnt/workspace/source/$TF_VAR_spacelift_project_root
|
|
184
|
-
spaceforge
|
|
184
|
+
spaceforge run --plugin-file /mnt/workspace/plugins/sops/plugin.py before_init
|
|
185
185
|
sensitive: false
|
|
186
186
|
hooks:
|
|
187
187
|
before_init:
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from spaceforge import Binary, Context, Parameter, Policy, SpaceforgePlugin, Variable
|
|
5
|
+
|
|
6
|
+
DEFAULT_TFLINT_CONFIG_FILE = ""
|
|
7
|
+
DEFAULT_TFLINT_RECURSIVE = "true"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TFLintPlugin(SpaceforgePlugin):
|
|
11
|
+
"""
|
|
12
|
+
# Plugin TFLint
|
|
13
|
+
|
|
14
|
+
The TFLint plugin analyzes your Terraform/OpenTofu files and generates a report with findings categorized by severity.
|
|
15
|
+
|
|
16
|
+
You can also access the data from a plan policy via the `input.third_party_metadata.custom.tflint` object.
|
|
17
|
+
An example Plan policy is included with the plugin.
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
1. Install the plugin
|
|
22
|
+
2. Add the `autoattach` label to any stack that uses Terraform/OpenTofu.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
__author__ = "Spacelift"
|
|
26
|
+
__labels__ = ["qa", "security"]
|
|
27
|
+
__plugin_name__ = "tflint"
|
|
28
|
+
__version__ = "0.1.0"
|
|
29
|
+
|
|
30
|
+
__binaries__ = [
|
|
31
|
+
Binary(
|
|
32
|
+
name="tflint",
|
|
33
|
+
download_urls={
|
|
34
|
+
"amd64": "https://github.com/terraform-linters/tflint/releases/download/v0.59.1/tflint_linux_amd64.zip",
|
|
35
|
+
"arm64": "https://github.com/terraform-linters/tflint/releases/download/v0.59.1/tflint_linux_arm64.zip",
|
|
36
|
+
},
|
|
37
|
+
),
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
__parameters__ = [
|
|
41
|
+
Parameter(
|
|
42
|
+
name="Configuration file",
|
|
43
|
+
id="tflint_config_file",
|
|
44
|
+
description="Configuration file name",
|
|
45
|
+
default=DEFAULT_TFLINT_CONFIG_FILE,
|
|
46
|
+
),
|
|
47
|
+
Parameter(
|
|
48
|
+
name="Recursive",
|
|
49
|
+
id="tflint_recursive",
|
|
50
|
+
description="Run command in each directory recursively. Allowed values: true, false",
|
|
51
|
+
default=DEFAULT_TFLINT_RECURSIVE,
|
|
52
|
+
),
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
__contexts__ = [
|
|
56
|
+
Context(
|
|
57
|
+
name_prefix="tflint",
|
|
58
|
+
description="TFLint Plugin",
|
|
59
|
+
env=[
|
|
60
|
+
Variable(
|
|
61
|
+
key="TFLINT_CONFIG_FILE",
|
|
62
|
+
value_from_parameter="tflint_config_file",
|
|
63
|
+
),
|
|
64
|
+
Variable(
|
|
65
|
+
key="TFLINT_RECURSIVE",
|
|
66
|
+
value_from_parameter="tflint_recursive",
|
|
67
|
+
),
|
|
68
|
+
],
|
|
69
|
+
)
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
__policies__ = [
|
|
73
|
+
Policy(
|
|
74
|
+
name_prefix="tflint",
|
|
75
|
+
type="PLAN",
|
|
76
|
+
labels=["tflint"],
|
|
77
|
+
body="""
|
|
78
|
+
package spacelift
|
|
79
|
+
|
|
80
|
+
import rego.v1
|
|
81
|
+
|
|
82
|
+
max_errors := 0
|
|
83
|
+
max_warnings := 0
|
|
84
|
+
max_notices := 3
|
|
85
|
+
|
|
86
|
+
issues := input.third_party_metadata.custom.tflint.issues
|
|
87
|
+
|
|
88
|
+
deny contains sprintf("Too many errors (%d)", [cnt]) if {
|
|
89
|
+
cnt := count([issue | issue := issues[_]; issue.rule.severity == "error"])
|
|
90
|
+
cnt > max_errors
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
deny contains sprintf("Too many warnings (%d)", [cnt]) if {
|
|
94
|
+
cnt := count([issue | issue := issues[_]; issue.rule.severity == "warning"])
|
|
95
|
+
cnt > max_warnings
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
deny contains sprintf("Too many notices (%d)", [cnt]) if {
|
|
99
|
+
cnt := count([issue | issue := issues[_]; issue.rule.severity == "notice"])
|
|
100
|
+
cnt > max_notices
|
|
101
|
+
}
|
|
102
|
+
""",
|
|
103
|
+
)
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
def before_plan(self):
|
|
107
|
+
try:
|
|
108
|
+
options = ["--format=json"]
|
|
109
|
+
|
|
110
|
+
# Configuration file
|
|
111
|
+
config_file = (
|
|
112
|
+
os.environ.get("TFLINT_CONFIG_FILE") or DEFAULT_TFLINT_CONFIG_FILE
|
|
113
|
+
)
|
|
114
|
+
if config_file:
|
|
115
|
+
options.append(f"--config={config_file}")
|
|
116
|
+
|
|
117
|
+
# Recursive
|
|
118
|
+
recursive = os.environ.get("TFLINT_RECURSIVE") or DEFAULT_TFLINT_RECURSIVE
|
|
119
|
+
if recursive == "true":
|
|
120
|
+
options.append("--recursive")
|
|
121
|
+
|
|
122
|
+
return_code, stdout, stderr = self.run_cli("tflint", "--init")
|
|
123
|
+
if return_code != 0:
|
|
124
|
+
self.logger.error(f"tflint --init failed with code {return_code}")
|
|
125
|
+
if stderr:
|
|
126
|
+
# Display stderr manually because output display is disabled
|
|
127
|
+
self.logger.error("\n".join(stderr))
|
|
128
|
+
exit(1)
|
|
129
|
+
|
|
130
|
+
return_code, stdout, stderr = self.run_cli(
|
|
131
|
+
"tflint", *options, print_output=False
|
|
132
|
+
)
|
|
133
|
+
stdout_json = json.loads("\n".join(stdout))
|
|
134
|
+
|
|
135
|
+
# KLUDGE: The `expect_code` argument does not support multiple values so we need to manually handle this.
|
|
136
|
+
# `0` means success and `2` means issues found which is informational, not a failure.
|
|
137
|
+
if return_code not in [0, 2]:
|
|
138
|
+
for error in stdout_json["errors"]:
|
|
139
|
+
self.logger.error(error["message"])
|
|
140
|
+
exit(1)
|
|
141
|
+
|
|
142
|
+
self.add_to_policy_input("tflint", stdout_json)
|
|
143
|
+
|
|
144
|
+
if len(stdout_json["issues"]) == 0:
|
|
145
|
+
self.logger.info("No issues found")
|
|
146
|
+
return
|
|
147
|
+
|
|
148
|
+
findings = {
|
|
149
|
+
"error": {},
|
|
150
|
+
"warning": {},
|
|
151
|
+
"notice": {},
|
|
152
|
+
}
|
|
153
|
+
for match in stdout_json["issues"]:
|
|
154
|
+
severity = match["rule"]["severity"]
|
|
155
|
+
rule_name = match["rule"]["name"]
|
|
156
|
+
|
|
157
|
+
if rule_name not in findings[severity]:
|
|
158
|
+
findings[severity][rule_name] = []
|
|
159
|
+
|
|
160
|
+
findings[severity][rule_name].append(match)
|
|
161
|
+
|
|
162
|
+
markdown = "# TFLint Findings\n\n"
|
|
163
|
+
for severity, rules in findings.items():
|
|
164
|
+
# Skip severity level if no issues were found
|
|
165
|
+
if len(rules) == 0:
|
|
166
|
+
continue
|
|
167
|
+
|
|
168
|
+
emoji = None
|
|
169
|
+
if severity == "notice":
|
|
170
|
+
emoji = "🟡"
|
|
171
|
+
elif severity == "warning":
|
|
172
|
+
emoji = "🟠"
|
|
173
|
+
elif severity == "error":
|
|
174
|
+
emoji = "🔴"
|
|
175
|
+
if emoji is not None:
|
|
176
|
+
markdown += f"## {emoji} {severity.title()} Findings\n\n"
|
|
177
|
+
else:
|
|
178
|
+
markdown += f"## {severity.title()} Findings\n\n"
|
|
179
|
+
|
|
180
|
+
for rule_name, issues in rules.items():
|
|
181
|
+
markdown += f"### {rule_name}\n\n"
|
|
182
|
+
for issue in issues:
|
|
183
|
+
markdown += f"- {issue['message']} _({issue['range']['filename']}:{issue['range']['start']['line']})_\n"
|
|
184
|
+
markdown += "\n"
|
|
185
|
+
|
|
186
|
+
result = self.send_markdown(markdown)
|
|
187
|
+
if result:
|
|
188
|
+
self.logger.info(
|
|
189
|
+
"Issues found. Check the Plugins Output tab for details."
|
|
190
|
+
)
|
|
191
|
+
else:
|
|
192
|
+
self.logger.error("Failed to upload plugin outputs")
|
|
193
|
+
except Exception as e:
|
|
194
|
+
self.logger.error(f"Plugin failed: {e}")
|
|
195
|
+
exit(1)
|