spaceforge 1.1.4__tar.gz → 1.1.5__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.
Files changed (62) hide show
  1. {spaceforge-1.1.4 → spaceforge-1.1.5}/PKG-INFO +1 -6
  2. spaceforge-1.1.5/spaceforge/_version.py +39 -0
  3. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/_version_scm.py +3 -3
  4. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge.egg-info/PKG-INFO +1 -6
  5. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge.egg-info/SOURCES.txt +0 -4
  6. spaceforge-1.1.4/plugins/tflint/plugin.py +0 -195
  7. spaceforge-1.1.4/plugins/tflint/plugin.yaml +0 -363
  8. spaceforge-1.1.4/setup.py +0 -66
  9. spaceforge-1.1.4/spaceforge/_version.py +0 -80
  10. spaceforge-1.1.4/spaceforge.egg-info/not-zip-safe +0 -1
  11. {spaceforge-1.1.4 → spaceforge-1.1.5}/.github/workflows/ci.yml +0 -0
  12. {spaceforge-1.1.4 → spaceforge-1.1.5}/.github/workflows/release.yml +0 -0
  13. {spaceforge-1.1.4 → spaceforge-1.1.5}/.gitignore +0 -0
  14. {spaceforge-1.1.4 → spaceforge-1.1.5}/LICENSE +0 -0
  15. {spaceforge-1.1.4 → spaceforge-1.1.5}/MANIFEST.in +0 -0
  16. {spaceforge-1.1.4 → spaceforge-1.1.5}/README.md +0 -0
  17. {spaceforge-1.1.4 → spaceforge-1.1.5}/go.mod +0 -0
  18. {spaceforge-1.1.4 → spaceforge-1.1.5}/plugins/enviroment_manager/plugin.py +0 -0
  19. {spaceforge-1.1.4 → spaceforge-1.1.5}/plugins/enviroment_manager/plugin.yaml +0 -0
  20. {spaceforge-1.1.4 → spaceforge-1.1.5}/plugins/enviroment_manager/requirements.txt +0 -0
  21. {spaceforge-1.1.4 → spaceforge-1.1.5}/plugins/envsubst/plugin.py +0 -0
  22. {spaceforge-1.1.4 → spaceforge-1.1.5}/plugins/envsubst/plugin.yaml +0 -0
  23. {spaceforge-1.1.4 → spaceforge-1.1.5}/plugins/infracost/plugin.py +0 -0
  24. {spaceforge-1.1.4 → spaceforge-1.1.5}/plugins/infracost/plugin.yaml +0 -0
  25. {spaceforge-1.1.4 → spaceforge-1.1.5}/plugins/sops/plugin.py +0 -0
  26. {spaceforge-1.1.4 → spaceforge-1.1.5}/plugins/sops/plugin.yaml +0 -0
  27. {spaceforge-1.1.4 → spaceforge-1.1.5}/plugins/sops/requirements.txt +0 -0
  28. {spaceforge-1.1.4 → spaceforge-1.1.5}/plugins/wiz/plugin.py +0 -0
  29. {spaceforge-1.1.4 → spaceforge-1.1.5}/plugins/wiz/plugin.yaml +0 -0
  30. {spaceforge-1.1.4 → spaceforge-1.1.5}/pyproject.toml +0 -0
  31. {spaceforge-1.1.4 → spaceforge-1.1.5}/setup.cfg +0 -0
  32. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/README.md +0 -0
  33. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/__init__.py +0 -0
  34. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/__main__.py +0 -0
  35. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/cls.py +0 -0
  36. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/conftest.py +0 -0
  37. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/generator.py +0 -0
  38. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/plugin.py +0 -0
  39. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/runner.py +0 -0
  40. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/schema.json +0 -0
  41. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/templates/binary_install.sh.j2 +0 -0
  42. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/templates/ensure_spaceforge_and_run.sh.j2 +0 -0
  43. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/test_cls.py +0 -0
  44. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/test_generator.py +0 -0
  45. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/test_generator_binaries.py +0 -0
  46. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/test_generator_core.py +0 -0
  47. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/test_generator_hooks.py +0 -0
  48. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/test_generator_parameters.py +0 -0
  49. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/test_plugin.py +0 -0
  50. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/test_plugin_file_operations.py +0 -0
  51. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/test_plugin_hooks.py +0 -0
  52. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/test_plugin_inheritance.py +0 -0
  53. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/test_runner.py +0 -0
  54. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/test_runner_cli.py +0 -0
  55. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/test_runner_core.py +0 -0
  56. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge/test_runner_execution.py +0 -0
  57. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge.egg-info/dependency_links.txt +0 -0
  58. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge.egg-info/entry_points.txt +0 -0
  59. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge.egg-info/requires.txt +0 -0
  60. {spaceforge-1.1.4 → spaceforge-1.1.5}/spaceforge.egg-info/top_level.txt +0 -0
  61. {spaceforge-1.1.4 → spaceforge-1.1.5}/templates.go +0 -0
  62. {spaceforge-1.1.4 → spaceforge-1.1.5}/test.sh +0 -0
@@ -1,9 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spaceforge
3
- Version: 1.1.4
3
+ Version: 1.1.5
4
4
  Summary: A Python framework for building Spacelift plugins
5
- Home-page: https://github.com/spacelift-io/plugins
6
- Author: Spacelift
7
5
  Author-email: Spacelift <support@spacelift.io>
8
6
  Maintainer-email: Spacelift <support@spacelift.io>
9
7
  License: MIT
@@ -39,10 +37,7 @@ Requires-Dist: mypy; extra == "dev"
39
37
  Requires-Dist: types-PyYAML; extra == "dev"
40
38
  Requires-Dist: setuptools-scm[toml]>=6.2; extra == "dev"
41
39
  Requires-Dist: autoflake; extra == "dev"
42
- Dynamic: author
43
- Dynamic: home-page
44
40
  Dynamic: license-file
45
- Dynamic: requires-python
46
41
 
47
42
  # Spaceforge - Build Spacelift Plugins in Python
48
43
 
@@ -0,0 +1,39 @@
1
+ """
2
+ Version detection using setuptools_scm.
3
+ """
4
+
5
+
6
+ def get_version() -> str:
7
+ """
8
+ Get the package version.
9
+
10
+ Uses setuptools_scm generated version file, which is created during build.
11
+ Falls back to a development version if not available.
12
+
13
+ Returns:
14
+ Version string
15
+ """
16
+ # Try setuptools-scm generated version file (created during build)
17
+ try:
18
+ from ._version_scm import version # type: ignore[import-not-found]
19
+
20
+ return str(version)
21
+ except ImportError:
22
+ pass
23
+
24
+ # Try setuptools-scm directly (works in development)
25
+ try:
26
+ from setuptools_scm import (
27
+ get_version as scm_get_version, # type: ignore[import-untyped]
28
+ )
29
+
30
+ result = scm_get_version(root="..", relative_to=__file__)
31
+ return str(result)
32
+ except ImportError:
33
+ pass
34
+ except Exception:
35
+ # setuptools_scm might fail in various ways, ignore
36
+ pass
37
+
38
+ # Fall back to default version for development
39
+ return "0.1.0-dev"
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '1.1.4'
32
- __version_tuple__ = version_tuple = (1, 1, 4)
31
+ __version__ = version = '1.1.5'
32
+ __version_tuple__ = version_tuple = (1, 1, 5)
33
33
 
34
- __commit_id__ = commit_id = 'ga236825db'
34
+ __commit_id__ = commit_id = 'gf45d03256'
@@ -1,9 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spaceforge
3
- Version: 1.1.4
3
+ Version: 1.1.5
4
4
  Summary: A Python framework for building Spacelift plugins
5
- Home-page: https://github.com/spacelift-io/plugins
6
- Author: Spacelift
7
5
  Author-email: Spacelift <support@spacelift.io>
8
6
  Maintainer-email: Spacelift <support@spacelift.io>
9
7
  License: MIT
@@ -39,10 +37,7 @@ Requires-Dist: mypy; extra == "dev"
39
37
  Requires-Dist: types-PyYAML; extra == "dev"
40
38
  Requires-Dist: setuptools-scm[toml]>=6.2; extra == "dev"
41
39
  Requires-Dist: autoflake; extra == "dev"
42
- Dynamic: author
43
- Dynamic: home-page
44
40
  Dynamic: license-file
45
- Dynamic: requires-python
46
41
 
47
42
  # Spaceforge - Build Spacelift Plugins in Python
48
43
 
@@ -4,7 +4,6 @@ MANIFEST.in
4
4
  README.md
5
5
  go.mod
6
6
  pyproject.toml
7
- setup.py
8
7
  templates.go
9
8
  test.sh
10
9
  .github/workflows/ci.yml
@@ -19,8 +18,6 @@ plugins/infracost/plugin.yaml
19
18
  plugins/sops/plugin.py
20
19
  plugins/sops/plugin.yaml
21
20
  plugins/sops/requirements.txt
22
- plugins/tflint/plugin.py
23
- plugins/tflint/plugin.yaml
24
21
  plugins/wiz/plugin.py
25
22
  plugins/wiz/plugin.yaml
26
23
  spaceforge/README.md
@@ -52,7 +49,6 @@ spaceforge.egg-info/PKG-INFO
52
49
  spaceforge.egg-info/SOURCES.txt
53
50
  spaceforge.egg-info/dependency_links.txt
54
51
  spaceforge.egg-info/entry_points.txt
55
- spaceforge.egg-info/not-zip-safe
56
52
  spaceforge.egg-info/requires.txt
57
53
  spaceforge.egg-info/top_level.txt
58
54
  spaceforge/templates/binary_install.sh.j2
@@ -1,195 +0,0 @@
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)
@@ -1,363 +0,0 @@
1
- name: tflint
2
- version: 0.1.0
3
- description: |-
4
- # Plugin TFLint
5
-
6
- The TFLint plugin analyzes your Terraform/OpenTofu files and generates a report with findings categorized by severity.
7
-
8
- You can also access the data from a plan policy via the `input.third_party_metadata.custom.tflint` object.
9
- An example Plan policy is included with the plugin.
10
-
11
- ## Usage
12
-
13
- 1. Install the plugin
14
- 2. Add the `autoattach` label to any stack that uses Terraform/OpenTofu.
15
- author: Spacelift
16
- labels:
17
- - qa
18
- - security
19
- parameters:
20
- - name: Configuration file
21
- description: Configuration file name
22
- sensitive: false
23
- required: false
24
- default: ''
25
- id: tflint_config_file
26
- - name: Recursive
27
- description: 'Run command in each directory recursively. Allowed values: true, false'
28
- sensitive: false
29
- required: false
30
- default: 'true'
31
- id: tflint_recursive
32
- contexts:
33
- - name_prefix: tflint
34
- description: TFLint Plugin
35
- env:
36
- - key: TFLINT_CONFIG_FILE
37
- value_from_parameter: tflint_config_file
38
- sensitive: false
39
- - key: TFLINT_RECURSIVE
40
- value_from_parameter: tflint_recursive
41
- sensitive: false
42
- mounted_files:
43
- - path: /mnt/workspace/plugins/tflint/plugin.py
44
- content: |-
45
- import json
46
- import os
47
-
48
- from spaceforge import Binary, Context, Parameter, Policy, SpaceforgePlugin, Variable
49
-
50
- DEFAULT_TFLINT_CONFIG_FILE = ""
51
- DEFAULT_TFLINT_RECURSIVE = "true"
52
-
53
-
54
- class TFLintPlugin(SpaceforgePlugin):
55
- """
56
- # Plugin TFLint
57
-
58
- The TFLint plugin analyzes your Terraform/OpenTofu files and generates a report with findings categorized by severity.
59
-
60
- You can also access the data from a plan policy via the `input.third_party_metadata.custom.tflint` object.
61
- An example Plan policy is included with the plugin.
62
-
63
- ## Usage
64
-
65
- 1. Install the plugin
66
- 2. Add the `autoattach` label to any stack that uses Terraform/OpenTofu.
67
- """
68
-
69
- __author__ = "Spacelift"
70
- __labels__ = ["qa", "security"]
71
- __plugin_name__ = "tflint"
72
- __version__ = "0.1.0"
73
-
74
- __binaries__ = [
75
- Binary(
76
- name="tflint",
77
- download_urls={
78
- "amd64": "https://github.com/terraform-linters/tflint/releases/download/v0.59.1/tflint_linux_amd64.zip",
79
- "arm64": "https://github.com/terraform-linters/tflint/releases/download/v0.59.1/tflint_linux_arm64.zip",
80
- },
81
- ),
82
- ]
83
-
84
- __parameters__ = [
85
- Parameter(
86
- name="Configuration file",
87
- id="tflint_config_file",
88
- description="Configuration file name",
89
- default=DEFAULT_TFLINT_CONFIG_FILE,
90
- ),
91
- Parameter(
92
- name="Recursive",
93
- id="tflint_recursive",
94
- description="Run command in each directory recursively. Allowed values: true, false",
95
- default=DEFAULT_TFLINT_RECURSIVE,
96
- ),
97
- ]
98
-
99
- __contexts__ = [
100
- Context(
101
- name_prefix="tflint",
102
- description="TFLint Plugin",
103
- env=[
104
- Variable(
105
- key="TFLINT_CONFIG_FILE",
106
- value_from_parameter="tflint_config_file",
107
- ),
108
- Variable(
109
- key="TFLINT_RECURSIVE",
110
- value_from_parameter="tflint_recursive",
111
- ),
112
- ],
113
- )
114
- ]
115
-
116
- __policies__ = [
117
- Policy(
118
- name_prefix="tflint",
119
- type="PLAN",
120
- labels=["tflint"],
121
- body="""
122
- package spacelift
123
-
124
- import rego.v1
125
-
126
- max_errors := 0
127
- max_warnings := 0
128
- max_notices := 3
129
-
130
- issues := input.third_party_metadata.custom.tflint.issues
131
-
132
- deny contains sprintf("Too many errors (%d)", [cnt]) if {
133
- cnt := count([issue | issue := issues[_]; issue.rule.severity == "error"])
134
- cnt > max_errors
135
- }
136
-
137
- deny contains sprintf("Too many warnings (%d)", [cnt]) if {
138
- cnt := count([issue | issue := issues[_]; issue.rule.severity == "warning"])
139
- cnt > max_warnings
140
- }
141
-
142
- deny contains sprintf("Too many notices (%d)", [cnt]) if {
143
- cnt := count([issue | issue := issues[_]; issue.rule.severity == "notice"])
144
- cnt > max_notices
145
- }
146
- """,
147
- )
148
- ]
149
-
150
- def before_plan(self):
151
- try:
152
- options = ["--format=json"]
153
-
154
- # Configuration file
155
- config_file = (
156
- os.environ.get("TFLINT_CONFIG_FILE") or DEFAULT_TFLINT_CONFIG_FILE
157
- )
158
- if config_file:
159
- options.append(f"--config={config_file}")
160
-
161
- # Recursive
162
- recursive = os.environ.get("TFLINT_RECURSIVE") or DEFAULT_TFLINT_RECURSIVE
163
- if recursive == "true":
164
- options.append("--recursive")
165
-
166
- return_code, stdout, stderr = self.run_cli("tflint", "--init")
167
- if return_code != 0:
168
- self.logger.error(f"tflint --init failed with code {return_code}")
169
- if stderr:
170
- # Display stderr manually because output display is disabled
171
- self.logger.error("\n".join(stderr))
172
- exit(1)
173
-
174
- return_code, stdout, stderr = self.run_cli(
175
- "tflint", *options, print_output=False
176
- )
177
- stdout_json = json.loads("\n".join(stdout))
178
-
179
- # KLUDGE: The `expect_code` argument does not support multiple values so we need to manually handle this.
180
- # `0` means success and `2` means issues found which is informational, not a failure.
181
- if return_code not in [0, 2]:
182
- for error in stdout_json["errors"]:
183
- self.logger.error(error["message"])
184
- exit(1)
185
-
186
- self.add_to_policy_input("tflint", stdout_json)
187
-
188
- if len(stdout_json["issues"]) == 0:
189
- self.logger.info("No issues found")
190
- return
191
-
192
- findings = {
193
- "error": {},
194
- "warning": {},
195
- "notice": {},
196
- }
197
- for match in stdout_json["issues"]:
198
- severity = match["rule"]["severity"]
199
- rule_name = match["rule"]["name"]
200
-
201
- if rule_name not in findings[severity]:
202
- findings[severity][rule_name] = []
203
-
204
- findings[severity][rule_name].append(match)
205
-
206
- markdown = "# TFLint Findings\n\n"
207
- for severity, rules in findings.items():
208
- # Skip severity level if no issues were found
209
- if len(rules) == 0:
210
- continue
211
-
212
- emoji = None
213
- if severity == "notice":
214
- emoji = "🟡"
215
- elif severity == "warning":
216
- emoji = "🟠"
217
- elif severity == "error":
218
- emoji = "🔴"
219
- if emoji is not None:
220
- markdown += f"## {emoji} {severity.title()} Findings\n\n"
221
- else:
222
- markdown += f"## {severity.title()} Findings\n\n"
223
-
224
- for rule_name, issues in rules.items():
225
- markdown += f"### {rule_name}\n\n"
226
- for issue in issues:
227
- markdown += f"- {issue['message']} _({issue['range']['filename']}:{issue['range']['start']['line']})_\n"
228
- markdown += "\n"
229
-
230
- result = self.send_markdown(markdown)
231
- if result:
232
- self.logger.info(
233
- "Issues found. Check the Plugins Output tab for details."
234
- )
235
- else:
236
- self.logger.error("Failed to upload plugin outputs")
237
- except Exception as e:
238
- self.logger.error(f"Plugin failed: {e}")
239
- exit(1)
240
- sensitive: false
241
- - path: /mnt/workspace/plugins/tflint/binary_install_tflint.sh
242
- content: |-
243
- #!/bin/sh
244
-
245
- set -e
246
-
247
- export PATH="/mnt/workspace/plugins/plugin_binaries:$PATH"
248
- if command -v tflint; then
249
- echo "tflint is already installed."
250
- return
251
- fi
252
-
253
- echo "Installing tflint..."
254
- mkdir -p /mnt/workspace/plugins/plugin_binaries
255
-
256
- ARCH="$(arch)"
257
- if [ "$ARCH" = "x86_64" ]; then
258
- URL="https://github.com/terraform-linters/tflint/releases/download/v0.59.1/tflint_linux_amd64.zip"
259
- elif [ "$ARCH" = "arm64" ]; then
260
- URL="https://github.com/terraform-linters/tflint/releases/download/v0.59.1/tflint_linux_arm64.zip"
261
- else
262
- echo "Error: Unsupported architecture '$ARCH'"
263
- exit 1
264
- fi
265
-
266
- case "$URL" in
267
- *.tar.gz|*.tar.bz2|*.zip)
268
- TMP_DIR=$(mktemp -d)
269
- trap 'rm -rf "$TMP_DIR"' EXIT
270
-
271
- ARCHIVE="$TMP_DIR/archive"
272
- curl "$URL" -o "$ARCHIVE" -fL
273
-
274
- case "$URL" in
275
- *.tar.gz)
276
- tar -xzf "$ARCHIVE" -C "$TMP_DIR" || { echo "Error: Failed to extract archive"; exit 1; }
277
- ;;
278
- *.tar.bz2)
279
- tar -xjf "$ARCHIVE" -C "$TMP_DIR" || { echo "Error: Failed to extract archive"; exit 1; }
280
- ;;
281
- *.zip)
282
- unzip -o "$ARCHIVE" -d "$TMP_DIR" || { echo "Error: Failed to extract archive"; exit 1; }
283
- ;;
284
- esac
285
-
286
- FOUND_BINARY=$(find "$TMP_DIR" -type f -name "tflint" | head -n 1)
287
- if [ -z "$FOUND_BINARY" ]; then
288
- echo "Error: Could not find binary 'tflint' in extracted archive"
289
- exit 1
290
- fi
291
-
292
- mv "$FOUND_BINARY" "/mnt/workspace/plugins/plugin_binaries/tflint"
293
- ;;
294
- *)
295
- curl "$URL" -o "/mnt/workspace/plugins/plugin_binaries/tflint" -fL
296
- ;;
297
- esac
298
-
299
- chmod +x "/mnt/workspace/plugins/plugin_binaries/tflint"
300
- sensitive: false
301
- - path: /mnt/workspace/plugins/tflint/before_plan.sh
302
- content: |-
303
- #!/bin/sh
304
-
305
- set -e
306
-
307
- cd /mnt/workspace/plugins/tflint
308
-
309
- if [ ! -d "./venv" ]; then
310
- python -m venv ./venv
311
- fi
312
- . venv/bin/activate
313
-
314
- if ! command -v spaceforge; then
315
- pip install spaceforge
316
- fi
317
-
318
- if [ -f requirements.txt ] && [ ! -f .spaceforge_installed_requirements ]; then
319
- pip install -r requirements.txt
320
- touch .spaceforge_installed_requirements
321
- fi
322
-
323
- export PATH="/mnt/workspace/plugins/plugin_binaries:$PATH"
324
-
325
- cd /mnt/workspace/source/$TF_VAR_spacelift_project_root
326
- spaceforge run --plugin-file /mnt/workspace/plugins/tflint/plugin.py before_plan
327
- sensitive: false
328
- hooks:
329
- before_init:
330
- - mkdir -p /mnt/workspace/plugins/tflint
331
- - chmod +x /mnt/workspace/plugins/tflint/binary_install_tflint.sh && /mnt/workspace/plugins/tflint/binary_install_tflint.sh
332
- before_plan:
333
- - chmod +x /mnt/workspace/plugins/tflint/before_plan.sh && /mnt/workspace/plugins/tflint/before_plan.sh
334
- policies:
335
- - name_prefix: tflint
336
- type: PLAN
337
- body: |-
338
- package spacelift
339
-
340
- import rego.v1
341
-
342
- max_errors := 0
343
- max_warnings := 0
344
- max_notices := 3
345
-
346
- issues := input.third_party_metadata.custom.tflint.issues
347
-
348
- deny contains sprintf("Too many errors (%d)", [cnt]) if {
349
- cnt := count([issue | issue := issues[_]; issue.rule.severity == "error"])
350
- cnt > max_errors
351
- }
352
-
353
- deny contains sprintf("Too many warnings (%d)", [cnt]) if {
354
- cnt := count([issue | issue := issues[_]; issue.rule.severity == "warning"])
355
- cnt > max_warnings
356
- }
357
-
358
- deny contains sprintf("Too many notices (%d)", [cnt]) if {
359
- cnt := count([issue | issue := issues[_]; issue.rule.severity == "notice"])
360
- cnt > max_notices
361
- }
362
- labels:
363
- - tflint
spaceforge-1.1.4/setup.py DELETED
@@ -1,66 +0,0 @@
1
- """
2
- Setup script for spaceforge - Spacelift Plugin Framework
3
- """
4
-
5
- from setuptools import setup, find_packages
6
-
7
- with open("README.md", "r", encoding="utf-8") as fh:
8
- long_description = fh.read()
9
-
10
- setup(
11
- name="spaceforge",
12
- author="Spacelift",
13
- author_email="support@spacelift.io",
14
- description="A Python framework for building Spacelift plugins",
15
- long_description=long_description,
16
- long_description_content_type="text/markdown",
17
- url="https://github.com/spacelift-io/plugins",
18
- project_urls={
19
- "Bug Reports": "https://github.com/spacelift-io/plugins/issues",
20
- "Source": "https://github.com/spacelift-io/plugins",
21
- },
22
- packages=find_packages(),
23
- package_data={
24
- "spaceforge": ["schema.json"],
25
- },
26
- include_package_data=True,
27
- classifiers=[
28
- "Development Status :: 3 - Alpha",
29
- "Intended Audience :: Developers",
30
- "License :: OSI Approved :: MIT License",
31
- "Operating System :: OS Independent",
32
- "Programming Language :: Python :: 3",
33
- "Programming Language :: Python :: 3.8",
34
- "Programming Language :: Python :: 3.9",
35
- "Programming Language :: Python :: 3.10",
36
- "Programming Language :: Python :: 3.11",
37
- "Programming Language :: Python :: 3.12",
38
- "Topic :: Software Development :: Libraries :: Python Modules",
39
- "Topic :: System :: Systems Administration",
40
- ],
41
- python_requires=">=3.9",
42
- install_requires=[
43
- "PyYAML>=6.0",
44
- "click>=8.0.0",
45
- "pydantic>=2.11.7",
46
- "Jinja2>=3.1.0",
47
- "mergedeep>=1.3.4",
48
- ],
49
- extras_require={
50
- "dev": [
51
- "pytest>=6.0",
52
- "pytest-cov",
53
- "black",
54
- "isort",
55
- "mypy",
56
- "autoflake"
57
- ],
58
- },
59
- entry_points={
60
- "console_scripts": [
61
- "spaceforge=spaceforge.__main__:main",
62
- ],
63
- },
64
- keywords="spacelift plugin framework infrastructure devops spaceforge",
65
- zip_safe=False,
66
- )
@@ -1,80 +0,0 @@
1
- """
2
- Dynamic version detection from git tags.
3
- """
4
-
5
- import subprocess
6
- from typing import Optional
7
-
8
-
9
- def get_git_version() -> Optional[str]:
10
- """
11
- Get version from git tags.
12
-
13
- Returns:
14
- Version string (without 'v' prefix) or None if not available
15
- """
16
- try:
17
- # Try to get the current tag
18
- result = subprocess.run(
19
- ["git", "describe", "--tags", "--exact-match"],
20
- capture_output=True,
21
- text=True,
22
- check=True,
23
- )
24
- tag = result.stdout.strip()
25
- # Remove 'v' prefix if present
26
- return tag[1:] if tag.startswith("v") else tag
27
- except (subprocess.CalledProcessError, FileNotFoundError):
28
- # Fall back to describe with commit info
29
- try:
30
- result = subprocess.run(
31
- ["git", "describe", "--tags", "--always"],
32
- capture_output=True,
33
- text=True,
34
- check=True,
35
- )
36
- tag = result.stdout.strip()
37
- # Remove 'v' prefix if present
38
- return tag[1:] if tag.startswith("v") else tag
39
- except (subprocess.CalledProcessError, FileNotFoundError):
40
- return None
41
-
42
-
43
- def get_version() -> str:
44
- """
45
- Get the package version.
46
-
47
- Tries git tags first, then setuptools-scm, falls back to default version.
48
-
49
- Returns:
50
- Version string
51
- """
52
- # Try git version first
53
- git_version = get_git_version()
54
- if git_version:
55
- return git_version
56
-
57
- # Try setuptools-scm generated version file
58
- try:
59
- from ._version_scm import version # type: ignore[import-not-found]
60
-
61
- return str(version)
62
- except ImportError:
63
- pass
64
-
65
- # Try setuptools-scm directly
66
- try:
67
- from setuptools_scm import (
68
- get_version as scm_get_version, # type: ignore[import-untyped]
69
- )
70
-
71
- result = scm_get_version(root="..", relative_to=__file__)
72
- return str(result)
73
- except ImportError:
74
- pass
75
- except Exception:
76
- # setuptools_scm might fail in various ways, ignore
77
- pass
78
-
79
- # Fall back to default version for development
80
- return "0.1.0-dev"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes