spaceforge 1.3.0__tar.gz → 1.4.0__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 (86) hide show
  1. spaceforge-1.4.0/CODEOWNERS +1 -0
  2. {spaceforge-1.3.0/spaceforge.egg-info → spaceforge-1.4.0}/PKG-INFO +1 -1
  3. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/sops/plugin.py +10 -1
  4. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/sops/plugin.yaml +17 -2
  5. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/wiz/plugin.py +131 -43
  6. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/wiz/plugin.yaml +196 -48
  7. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/_version_scm.py +3 -3
  8. {spaceforge-1.3.0 → spaceforge-1.4.0/spaceforge.egg-info}/PKG-INFO +1 -1
  9. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge.egg-info/SOURCES.txt +1 -0
  10. {spaceforge-1.3.0 → spaceforge-1.4.0}/.github/workflows/ci.yml +0 -0
  11. {spaceforge-1.3.0 → spaceforge-1.4.0}/.github/workflows/release.yml +0 -0
  12. {spaceforge-1.3.0 → spaceforge-1.4.0}/.gitignore +0 -0
  13. {spaceforge-1.3.0 → spaceforge-1.4.0}/CONTRIBUTING.md +0 -0
  14. {spaceforge-1.3.0 → spaceforge-1.4.0}/LICENSE +0 -0
  15. {spaceforge-1.3.0 → spaceforge-1.4.0}/MANIFEST.in +0 -0
  16. {spaceforge-1.3.0 → spaceforge-1.4.0}/README.md +0 -0
  17. {spaceforge-1.3.0 → spaceforge-1.4.0}/go.mod +0 -0
  18. {spaceforge-1.3.0 → spaceforge-1.4.0}/linting/__init__.py +0 -0
  19. {spaceforge-1.3.0 → spaceforge-1.4.0}/linting/spaceforge_checker.py +0 -0
  20. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/aws_sam/README.md +0 -0
  21. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/aws_sam/plugin.py +0 -0
  22. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/aws_sam/plugin.yaml +0 -0
  23. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/aws_sam/requirements.txt +0 -0
  24. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/checkov/README.md +0 -0
  25. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/checkov/plugin.py +0 -0
  26. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/checkov/plugin.yaml +0 -0
  27. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/checkov/requirements.txt +0 -0
  28. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/enviroment_manager/plugin.py +0 -0
  29. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/enviroment_manager/plugin.yaml +0 -0
  30. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/enviroment_manager/requirements.txt +0 -0
  31. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/envsubst/plugin.py +0 -0
  32. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/envsubst/plugin.yaml +0 -0
  33. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/infracost/plugin.py +0 -0
  34. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/infracost/plugin.yaml +0 -0
  35. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/opentofu-tracing/plugin.py +0 -0
  36. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/opentofu-tracing/plugin.yaml +0 -0
  37. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/sops/requirements.txt +0 -0
  38. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/ssm_parameter_store/README.md +0 -0
  39. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/ssm_parameter_store/plugin.py +0 -0
  40. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/ssm_parameter_store/plugin.yaml +0 -0
  41. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/ssm_parameter_store/requirements.txt +0 -0
  42. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/terrascan/README.md +0 -0
  43. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/terrascan/plugin.py +0 -0
  44. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/terrascan/plugin.yaml +0 -0
  45. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/trivy/README.md +0 -0
  46. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/trivy/plugin.py +0 -0
  47. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/trivy/plugin.yaml +0 -0
  48. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/trufflehog/README.md +0 -0
  49. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/trufflehog/plugin.py +0 -0
  50. {spaceforge-1.3.0 → spaceforge-1.4.0}/plugins/trufflehog/plugin.yaml +0 -0
  51. {spaceforge-1.3.0 → spaceforge-1.4.0}/pyproject.toml +0 -0
  52. {spaceforge-1.3.0 → spaceforge-1.4.0}/regenerate_plugins.sh +0 -0
  53. {spaceforge-1.3.0 → spaceforge-1.4.0}/setup.cfg +0 -0
  54. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/README.md +0 -0
  55. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/__init__.py +0 -0
  56. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/__main__.py +0 -0
  57. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/_version.py +0 -0
  58. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/cls.py +0 -0
  59. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/conftest.py +0 -0
  60. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/generator.py +0 -0
  61. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/plugin.py +0 -0
  62. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/runner.py +0 -0
  63. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/schema.json +0 -0
  64. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/templates/binary_install.sh.j2 +0 -0
  65. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/templates/ensure_spaceforge_and_run.sh.j2 +0 -0
  66. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/test_cls.py +0 -0
  67. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/test_generator.py +0 -0
  68. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/test_generator_binaries.py +0 -0
  69. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/test_generator_core.py +0 -0
  70. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/test_generator_hooks.py +0 -0
  71. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/test_generator_parameters.py +0 -0
  72. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/test_plugin.py +0 -0
  73. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/test_plugin_file_operations.py +0 -0
  74. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/test_plugin_hooks.py +0 -0
  75. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/test_plugin_inheritance.py +0 -0
  76. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/test_runner.py +0 -0
  77. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/test_runner_cli.py +0 -0
  78. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/test_runner_core.py +0 -0
  79. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge/test_runner_execution.py +0 -0
  80. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge.egg-info/dependency_links.txt +0 -0
  81. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge.egg-info/entry_points.txt +0 -0
  82. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge.egg-info/requires.txt +0 -0
  83. {spaceforge-1.3.0 → spaceforge-1.4.0}/spaceforge.egg-info/top_level.txt +0 -0
  84. {spaceforge-1.3.0 → spaceforge-1.4.0}/templates.go +0 -0
  85. {spaceforge-1.3.0 → spaceforge-1.4.0}/test.sh +0 -0
  86. {spaceforge-1.3.0 → spaceforge-1.4.0}/validate_plugins.py +0 -0
@@ -0,0 +1 @@
1
+ * @spacelift-io/ecosystem
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spaceforge
3
- Version: 1.3.0
3
+ Version: 1.4.0
4
4
  Summary: A Python framework for building Spacelift plugins
5
5
  Author-email: Spacelift <support@spacelift.io>
6
6
  Maintainer-email: Spacelift <support@spacelift.io>
@@ -43,12 +43,18 @@ class SopsPlugin(SpaceforgePlugin):
43
43
  file is at the repository root.
44
44
 
45
45
  Example: `${TF_VAR_spacelift_workspace_root}/source/.sops.yaml`
46
+
47
+ Environment variables are supported in the `secrets` list using `$VAR` or `${VAR}` syntax:
48
+ ```yaml
49
+ secrets:
50
+ - services/${TF_VAR_service_name}/secrets/${TF_VAR_environment}.enc.yaml
51
+ ```
46
52
  """
47
53
 
48
54
  # Plugin metadata
49
55
  __plugin_name__ = "Sops"
50
56
  __labels__ = ["secrets management", "encryption"]
51
- __version__ = "1.1.1"
57
+ __version__ = "1.2.0"
52
58
  __author__ = "Spacelift Team"
53
59
 
54
60
  __binaries__ = [
@@ -107,6 +113,9 @@ class SopsPlugin(SpaceforgePlugin):
107
113
  secrets = secrets["secrets"]
108
114
 
109
115
  for secret in secrets:
116
+ # Expand environment variables in secret paths (supports $VAR and ${VAR} syntax)
117
+ secret = os.path.expandvars(secret)
118
+
110
119
  if not Path(secret).exists():
111
120
  self.logger.error(f"Secret file {secret} does not exist.")
112
121
  continue
@@ -1,5 +1,5 @@
1
1
  name: Sops
2
- version: 1.1.1
2
+ version: 1.2.0
3
3
  description: |-
4
4
  This adds the `SOPS` plugin to your Spacelift account.
5
5
  It will decrypt an arbitrary number of files based on config you set.
@@ -35,6 +35,12 @@ description: |-
35
35
  file is at the repository root.
36
36
 
37
37
  Example: `${TF_VAR_spacelift_workspace_root}/source/.sops.yaml`
38
+
39
+ Environment variables are supported in the `secrets` list using `$VAR` or `${VAR}` syntax:
40
+ ```yaml
41
+ secrets:
42
+ - services/${TF_VAR_service_name}/secrets/${TF_VAR_environment}.enc.yaml
43
+ ```
38
44
  author: Spacelift Team
39
45
  labels:
40
46
  - secrets management
@@ -107,12 +113,18 @@ contexts:
107
113
  file is at the repository root.
108
114
 
109
115
  Example: `${TF_VAR_spacelift_workspace_root}/source/.sops.yaml`
116
+
117
+ Environment variables are supported in the `secrets` list using `$VAR` or `${VAR}` syntax:
118
+ ```yaml
119
+ secrets:
120
+ - services/${TF_VAR_service_name}/secrets/${TF_VAR_environment}.enc.yaml
121
+ ```
110
122
  """
111
123
 
112
124
  # Plugin metadata
113
125
  __plugin_name__ = "Sops"
114
126
  __labels__ = ["secrets management", "encryption"]
115
- __version__ = "1.1.1"
127
+ __version__ = "1.2.0"
116
128
  __author__ = "Spacelift Team"
117
129
 
118
130
  __binaries__ = [
@@ -171,6 +183,9 @@ contexts:
171
183
  secrets = secrets["secrets"]
172
184
 
173
185
  for secret in secrets:
186
+ # Expand environment variables in secret paths (supports $VAR and ${VAR} syntax)
187
+ secret = os.path.expandvars(secret)
188
+
174
189
  if not Path(secret).exists():
175
190
  self.logger.error(f"Secret file {secret} does not exist.")
176
191
  continue
@@ -23,28 +23,46 @@ class WizPlugin(SpaceforgePlugin):
23
23
  # Plugin metadata
24
24
  __plugin_name__ = "Wiz"
25
25
  __labels__ = ["security", "code scanning", "vulnerability"]
26
- __version__ = "1.0.4"
26
+ __version__ = "2.0.0"
27
27
  __author__ = "Spacelift Team"
28
28
 
29
29
  __binaries__ = [
30
30
  Binary(
31
31
  name="wizcli",
32
32
  download_urls={
33
- "amd64": "https://downloads.wiz.io/wizcli/latest/wizcli-linux-amd64",
34
- "arm64": "https://downloads.wiz.io/wizcli/latest/wizcli-linux-arm64",
33
+ "amd64": "https://downloads.wiz.io/v1/wizcli/latest/wizcli-linux-amd64",
34
+ "arm64": "https://downloads.wiz.io/v1/wizcli/latest/wizcli-linux-arm64",
35
35
  },
36
36
  )
37
37
  ]
38
38
 
39
39
  # Plugin parameters
40
40
  __parameters__ = [
41
+ Parameter(
42
+ name="Default Scan Name",
43
+ id="default_scan_name",
44
+ description="The default name of the scan that shows up in wiz. This setting can be overridden on individual stacks by manually setting the environment variable (DEFAULT_SCAN_NAME) there",
45
+ default="",
46
+ type="string",
47
+ required=False,
48
+ sensitive=False,
49
+ ),
50
+ Parameter(
51
+ name="Default Policies",
52
+ id="default_policies",
53
+ description="Comma separated list of policies to include in all scans. This setting can be overridden on individual stacks by manually setting the environment variable (DEFAULT_POLICIES) there.",
54
+ default="",
55
+ type="string",
56
+ required=False,
57
+ sensitive=False,
58
+ ),
41
59
  Parameter(
42
60
  name="Wiz Client ID",
43
61
  id="wiz_client_id",
44
62
  description="The client ID for Wiz API authentication",
45
63
  type="string",
46
64
  required=True,
47
- sensitive=True,
65
+ sensitive=False,
48
66
  ),
49
67
  Parameter(
50
68
  name="Wiz Client Secret",
@@ -54,6 +72,41 @@ class WizPlugin(SpaceforgePlugin):
54
72
  required=True,
55
73
  sensitive=True,
56
74
  ),
75
+ Parameter(
76
+ name="Additional Arguments",
77
+ id="wiz_additional_args",
78
+ description="Additional command-line arguments to pass to Wiz",
79
+ default="",
80
+ type="string",
81
+ required=False,
82
+ ),
83
+ Parameter(
84
+ name="Wiz CLI Autofail",
85
+ id="wizcli_autofail",
86
+ description="Allow wizcli to fail the run (instead of policies)",
87
+ default=False,
88
+ type="boolean",
89
+ required=False,
90
+ sensitive=False,
91
+ ),
92
+ Parameter(
93
+ name="Is GovCloud",
94
+ id="is_govcloud",
95
+ description="Enable if you access wiz via gov.wiz.io",
96
+ default=False,
97
+ type="boolean",
98
+ required=False,
99
+ sensitive=False,
100
+ ),
101
+ Parameter(
102
+ name="Is Fedramp",
103
+ id="is_fedramp",
104
+ description="Enable if you access wiz via app.wiz.us",
105
+ default=False,
106
+ type="boolean",
107
+ required=False,
108
+ sensitive=False,
109
+ ),
57
110
  ]
58
111
 
59
112
  # Plugin contexts
@@ -62,16 +115,46 @@ class WizPlugin(SpaceforgePlugin):
62
115
  name_prefix="WIZ",
63
116
  description="Wiz Plugin",
64
117
  env=[
118
+ Variable(
119
+ key="DEFAULT_SCAN_NAME",
120
+ value_from_parameter="default_scan_name",
121
+ sensitive=False,
122
+ ),
123
+ Variable(
124
+ key="DEFAULT_POLICIES",
125
+ value_from_parameter="default_policies",
126
+ sensitive=False,
127
+ ),
65
128
  Variable(
66
129
  key="WIZ_CLIENT_ID",
67
- value_from_parameter="Wiz Client ID",
68
- sensitive=True,
130
+ value_from_parameter="wiz_client_id",
131
+ sensitive=False,
69
132
  ),
70
133
  Variable(
71
134
  key="WIZ_CLIENT_SECRET",
72
- value_from_parameter="Wiz Client Secret",
135
+ value_from_parameter="wiz_client_secret",
73
136
  sensitive=True,
74
137
  ),
138
+ Variable(
139
+ key="WIZ_ADDITIONAL_ARGS",
140
+ value_from_parameter="wiz_additional_args",
141
+ sensitive=False,
142
+ ),
143
+ Variable(
144
+ key="WIZCLI_AUTOFAIL",
145
+ value_from_parameter="wizcli_autofail",
146
+ sensitive=False,
147
+ ),
148
+ Variable(
149
+ key="IS_GOVCLOUD",
150
+ value_from_parameter="is_govcloud",
151
+ sensitive=False,
152
+ ),
153
+ Variable(
154
+ key="IS_FEDRAMP",
155
+ value_from_parameter="is_fedramp",
156
+ sensitive=False,
157
+ ),
75
158
  ],
76
159
  )
77
160
  ]
@@ -119,63 +202,68 @@ deny[sprintf("Too many low vulnerabilities (%d)", [num])] {
119
202
  def before_plan(self):
120
203
  self.logger.info("Checking IAC Code")
121
204
 
122
- return_code, stdout, stderr = self.run_cli(
123
- "wizcli",
124
- "auth",
125
- "--id",
126
- os.environ.get("WIZ_CLIENT_ID"),
127
- "--secret",
128
- os.environ.get("WIZ_CLIENT_SECRET"),
129
- )
130
- if return_code != 0:
131
- exit(1)
205
+ if os.environ.get("IS_GOVCLOUD", "false").lower() == "true":
206
+ os.environ["WIZ_ENV"] = "gov"
207
+
208
+ if os.environ.get("IS_FEDRAMP", "false").lower() == "true":
209
+ os.environ["WIZ_ENV"] = "fedramp"
132
210
 
133
- return_code, stdout, stderr = self.run_cli(
211
+ args = [
134
212
  "wizcli",
135
- "iac",
136
213
  "scan",
137
- "--format",
138
- "json",
139
- "--path",
214
+ "dir",
140
215
  "./",
216
+ "--json-output-file",
217
+ "./wiz_scan.json",
141
218
  "--no-style",
142
219
  "--no-color",
143
220
  "--no-telemetry",
144
- "--show-secret-snippets",
145
- print_output=False,
146
- )
147
- if return_code != 0:
221
+ "--no-browser",
222
+ ]
223
+
224
+ if os.environ.get("DEFAULT_SCAN_NAME", "") != "":
225
+ args.extend(["--name", os.environ.get("DEFAULT_SCAN_NAME")])
226
+
227
+ if os.environ.get("DEFAULT_POLICIES", "") != "":
228
+ args.extend(["--policies", os.environ.get("DEFAULT_POLICIES")])
229
+
230
+ additional_args = os.environ.get("WIZ_ADDITIONAL_ARGS", "").strip()
231
+ if additional_args:
232
+ args.extend(additional_args.split())
233
+
234
+ return_code, stdout, stderr = self.run_cli(*args, print_output=False)
235
+ if (
236
+ os.environ.get("WIZCLI_AUTOFAIL", "false").lower() == "true"
237
+ and return_code != 0
238
+ ):
148
239
  # Print the output because we set print_output=False because wizcli outputs errors to stdout.
149
240
  for line in stdout:
150
241
  self.logger.error(line)
151
242
  exit(1)
152
243
 
153
- stdout_json = None
154
- for line in stdout:
155
- try:
156
- stdout_json = json.loads(line)
157
- break
158
- except json.decoder.JSONDecodeError:
159
- stdout_json = None
244
+ with open("wiz_scan.json", "r") as f:
245
+ results = json.load(f)
246
+
247
+ self.logger.debug(results)
160
248
 
161
- if stdout_json is None:
249
+ if results is None:
162
250
  self.logger.error("Failed to parse Wiz CLI output as JSON")
163
- self.logger.debug(stdout)
251
+ self.logger.debug(stdout, results)
164
252
  exit(1)
165
253
 
166
- if "result" not in stdout_json or "ruleMatches" not in stdout_json["result"]:
254
+ if "result" not in results or "ruleMatches" not in results["result"]:
167
255
  self.logger.error("Unexpected Wiz CLI output format")
168
- self.logger.debug(stdout_json)
256
+ self.logger.debug(results)
169
257
  exit(1)
170
258
 
171
- self.add_to_policy_input("wiz", stdout_json)
259
+ self.add_to_policy_input("wiz", results)
172
260
 
173
- if stdout_json["result"]["ruleMatches"] is None:
261
+ if results["result"]["ruleMatches"] is None:
174
262
  self.logger.info("No findings found in the IAC scan.")
175
263
  else:
176
264
  findings = {}
177
265
  # Sort the findings by the severity and their rule id
178
- for match in stdout_json["result"]["ruleMatches"]:
266
+ for match in results["result"]["ruleMatches"]:
179
267
  if match["severity"] not in findings:
180
268
  findings[match["severity"]] = {}
181
269
  if match["rule"]["id"] not in findings[match["severity"]]:
@@ -188,7 +276,7 @@ deny[sprintf("Too many low vulnerabilities (%d)", [num])] {
188
276
  )
189
277
 
190
278
  markdown = "# Wiz IAC Scan Findings\n\n"
191
- markdown += f"**Status:** {stdout_json['status']['state']} **Verdict:** {stdout_json['status']['verdict']}\n"
279
+ markdown += f"**Status:** {results['status']['state']} **Verdict:** {results['status']['verdict']}\n"
192
280
  for severity, matches in findings.items():
193
281
  severity = severity.upper()
194
282
 
@@ -214,8 +302,8 @@ deny[sprintf("Too many low vulnerabilities (%d)", [num])] {
214
302
  for match in cycled_rule["matches"]:
215
303
  markdown += f"- File: {match['fileName']}, Line: {match['lineNumber']}\n"
216
304
  markdown += "\n"
217
- if "reportUrl" in stdout_json:
218
- markdown += f"[View Report]({stdout_json['reportUrl']})\n"
305
+ if "reportUrl" in results:
306
+ markdown += f"[View Report]({results['reportUrl']})\n"
219
307
  result = self.send_markdown(markdown)
220
308
  if not result:
221
309
  self.logger.error("Failed to send Wiz CLI output to spacelift")
@@ -1,5 +1,5 @@
1
1
  name: Wiz
2
- version: 1.0.4
2
+ version: 2.0.0
3
3
  description: |-
4
4
  This adds the `wiz` plugin to your Spacelift account.
5
5
  It will scan your infrastructure as code (IaC) for vulnerabilities using Wiz CLI, generating a report of findings and
@@ -19,10 +19,24 @@ labels:
19
19
  - code scanning
20
20
  - vulnerability
21
21
  parameters:
22
+ - name: Default Scan Name
23
+ description: The default name of the scan that shows up in wiz. This setting can be overridden on individual stacks by manually setting the environment variable (DEFAULT_SCAN_NAME) there
24
+ type: string
25
+ sensitive: false
26
+ required: false
27
+ default: ''
28
+ id: default_scan_name
29
+ - name: Default Policies
30
+ description: Comma separated list of policies to include in all scans. This setting can be overridden on individual stacks by manually setting the environment variable (DEFAULT_POLICIES) there.
31
+ type: string
32
+ sensitive: false
33
+ required: false
34
+ default: ''
35
+ id: default_policies
22
36
  - name: Wiz Client ID
23
37
  description: The client ID for Wiz API authentication
24
38
  type: string
25
- sensitive: true
39
+ sensitive: false
26
40
  required: true
27
41
  id: wiz_client_id
28
42
  - name: Wiz Client Secret
@@ -31,16 +45,62 @@ parameters:
31
45
  sensitive: true
32
46
  required: true
33
47
  id: wiz_client_secret
48
+ - name: Additional Arguments
49
+ description: Additional command-line arguments to pass to Wiz
50
+ type: string
51
+ sensitive: false
52
+ required: false
53
+ default: ''
54
+ id: wiz_additional_args
55
+ - name: Wiz CLI Autofail
56
+ description: Allow wizcli to fail the run (instead of policies)
57
+ type: boolean
58
+ sensitive: false
59
+ required: false
60
+ default: false
61
+ id: wizcli_autofail
62
+ - name: Is GovCloud
63
+ description: Enable if you access wiz via gov.wiz.io
64
+ type: boolean
65
+ sensitive: false
66
+ required: false
67
+ default: false
68
+ id: is_govcloud
69
+ - name: Is Fedramp
70
+ description: Enable if you access wiz via app.wiz.us
71
+ type: boolean
72
+ sensitive: false
73
+ required: false
74
+ default: false
75
+ id: is_fedramp
34
76
  contexts:
35
77
  - name_prefix: WIZ
36
78
  description: Wiz Plugin
37
79
  env:
80
+ - key: DEFAULT_SCAN_NAME
81
+ value_from_parameter: default_scan_name
82
+ sensitive: false
83
+ - key: DEFAULT_POLICIES
84
+ value_from_parameter: default_policies
85
+ sensitive: false
38
86
  - key: WIZ_CLIENT_ID
39
87
  value_from_parameter: wiz_client_id
40
- sensitive: true
88
+ sensitive: false
41
89
  - key: WIZ_CLIENT_SECRET
42
90
  value_from_parameter: wiz_client_secret
43
91
  sensitive: true
92
+ - key: WIZ_ADDITIONAL_ARGS
93
+ value_from_parameter: wiz_additional_args
94
+ sensitive: false
95
+ - key: WIZCLI_AUTOFAIL
96
+ value_from_parameter: wizcli_autofail
97
+ sensitive: false
98
+ - key: IS_GOVCLOUD
99
+ value_from_parameter: is_govcloud
100
+ sensitive: false
101
+ - key: IS_FEDRAMP
102
+ value_from_parameter: is_fedramp
103
+ sensitive: false
44
104
  mounted_files:
45
105
  - path: /mnt/workspace/plugins/wiz/plugin.py
46
106
  content: |-
@@ -69,28 +129,46 @@ contexts:
69
129
  # Plugin metadata
70
130
  __plugin_name__ = "Wiz"
71
131
  __labels__ = ["security", "code scanning", "vulnerability"]
72
- __version__ = "1.0.4"
132
+ __version__ = "2.0.0"
73
133
  __author__ = "Spacelift Team"
74
134
 
75
135
  __binaries__ = [
76
136
  Binary(
77
137
  name="wizcli",
78
138
  download_urls={
79
- "amd64": "https://downloads.wiz.io/wizcli/latest/wizcli-linux-amd64",
80
- "arm64": "https://downloads.wiz.io/wizcli/latest/wizcli-linux-arm64",
139
+ "amd64": "https://downloads.wiz.io/v1/wizcli/latest/wizcli-linux-amd64",
140
+ "arm64": "https://downloads.wiz.io/v1/wizcli/latest/wizcli-linux-arm64",
81
141
  },
82
142
  )
83
143
  ]
84
144
 
85
145
  # Plugin parameters
86
146
  __parameters__ = [
147
+ Parameter(
148
+ name="Default Scan Name",
149
+ id="default_scan_name",
150
+ description="The default name of the scan that shows up in wiz. This setting can be overridden on individual stacks by manually setting the environment variable (DEFAULT_SCAN_NAME) there",
151
+ default="",
152
+ type="string",
153
+ required=False,
154
+ sensitive=False,
155
+ ),
156
+ Parameter(
157
+ name="Default Policies",
158
+ id="default_policies",
159
+ description="Comma separated list of policies to include in all scans. This setting can be overridden on individual stacks by manually setting the environment variable (DEFAULT_POLICIES) there.",
160
+ default="",
161
+ type="string",
162
+ required=False,
163
+ sensitive=False,
164
+ ),
87
165
  Parameter(
88
166
  name="Wiz Client ID",
89
167
  id="wiz_client_id",
90
168
  description="The client ID for Wiz API authentication",
91
169
  type="string",
92
170
  required=True,
93
- sensitive=True,
171
+ sensitive=False,
94
172
  ),
95
173
  Parameter(
96
174
  name="Wiz Client Secret",
@@ -100,6 +178,41 @@ contexts:
100
178
  required=True,
101
179
  sensitive=True,
102
180
  ),
181
+ Parameter(
182
+ name="Additional Arguments",
183
+ id="wiz_additional_args",
184
+ description="Additional command-line arguments to pass to Wiz",
185
+ default="",
186
+ type="string",
187
+ required=False,
188
+ ),
189
+ Parameter(
190
+ name="Wiz CLI Autofail",
191
+ id="wizcli_autofail",
192
+ description="Allow wizcli to fail the run (instead of policies)",
193
+ default=False,
194
+ type="boolean",
195
+ required=False,
196
+ sensitive=False,
197
+ ),
198
+ Parameter(
199
+ name="Is GovCloud",
200
+ id="is_govcloud",
201
+ description="Enable if you access wiz via gov.wiz.io",
202
+ default=False,
203
+ type="boolean",
204
+ required=False,
205
+ sensitive=False,
206
+ ),
207
+ Parameter(
208
+ name="Is Fedramp",
209
+ id="is_fedramp",
210
+ description="Enable if you access wiz via app.wiz.us",
211
+ default=False,
212
+ type="boolean",
213
+ required=False,
214
+ sensitive=False,
215
+ ),
103
216
  ]
104
217
 
105
218
  # Plugin contexts
@@ -108,16 +221,46 @@ contexts:
108
221
  name_prefix="WIZ",
109
222
  description="Wiz Plugin",
110
223
  env=[
224
+ Variable(
225
+ key="DEFAULT_SCAN_NAME",
226
+ value_from_parameter="default_scan_name",
227
+ sensitive=False,
228
+ ),
229
+ Variable(
230
+ key="DEFAULT_POLICIES",
231
+ value_from_parameter="default_policies",
232
+ sensitive=False,
233
+ ),
111
234
  Variable(
112
235
  key="WIZ_CLIENT_ID",
113
- value_from_parameter="Wiz Client ID",
114
- sensitive=True,
236
+ value_from_parameter="wiz_client_id",
237
+ sensitive=False,
115
238
  ),
116
239
  Variable(
117
240
  key="WIZ_CLIENT_SECRET",
118
- value_from_parameter="Wiz Client Secret",
241
+ value_from_parameter="wiz_client_secret",
119
242
  sensitive=True,
120
243
  ),
244
+ Variable(
245
+ key="WIZ_ADDITIONAL_ARGS",
246
+ value_from_parameter="wiz_additional_args",
247
+ sensitive=False,
248
+ ),
249
+ Variable(
250
+ key="WIZCLI_AUTOFAIL",
251
+ value_from_parameter="wizcli_autofail",
252
+ sensitive=False,
253
+ ),
254
+ Variable(
255
+ key="IS_GOVCLOUD",
256
+ value_from_parameter="is_govcloud",
257
+ sensitive=False,
258
+ ),
259
+ Variable(
260
+ key="IS_FEDRAMP",
261
+ value_from_parameter="is_fedramp",
262
+ sensitive=False,
263
+ ),
121
264
  ],
122
265
  )
123
266
  ]
@@ -165,63 +308,68 @@ contexts:
165
308
  def before_plan(self):
166
309
  self.logger.info("Checking IAC Code")
167
310
 
168
- return_code, stdout, stderr = self.run_cli(
169
- "wizcli",
170
- "auth",
171
- "--id",
172
- os.environ.get("WIZ_CLIENT_ID"),
173
- "--secret",
174
- os.environ.get("WIZ_CLIENT_SECRET"),
175
- )
176
- if return_code != 0:
177
- exit(1)
311
+ if os.environ.get("IS_GOVCLOUD", "false").lower() == "true":
312
+ os.environ["WIZ_ENV"] = "gov"
313
+
314
+ if os.environ.get("IS_FEDRAMP", "false").lower() == "true":
315
+ os.environ["WIZ_ENV"] = "fedramp"
178
316
 
179
- return_code, stdout, stderr = self.run_cli(
317
+ args = [
180
318
  "wizcli",
181
- "iac",
182
319
  "scan",
183
- "--format",
184
- "json",
185
- "--path",
320
+ "dir",
186
321
  "./",
322
+ "--json-output-file",
323
+ "./wiz_scan.json",
187
324
  "--no-style",
188
325
  "--no-color",
189
326
  "--no-telemetry",
190
- "--show-secret-snippets",
191
- print_output=False,
192
- )
193
- if return_code != 0:
327
+ "--no-browser",
328
+ ]
329
+
330
+ if os.environ.get("DEFAULT_SCAN_NAME", "") != "":
331
+ args.extend(["--name", os.environ.get("DEFAULT_SCAN_NAME")])
332
+
333
+ if os.environ.get("DEFAULT_POLICIES", "") != "":
334
+ args.extend(["--policies", os.environ.get("DEFAULT_POLICIES")])
335
+
336
+ additional_args = os.environ.get("WIZ_ADDITIONAL_ARGS", "").strip()
337
+ if additional_args:
338
+ args.extend(additional_args.split())
339
+
340
+ return_code, stdout, stderr = self.run_cli(*args, print_output=False)
341
+ if (
342
+ os.environ.get("WIZCLI_AUTOFAIL", "false").lower() == "true"
343
+ and return_code != 0
344
+ ):
194
345
  # Print the output because we set print_output=False because wizcli outputs errors to stdout.
195
346
  for line in stdout:
196
347
  self.logger.error(line)
197
348
  exit(1)
198
349
 
199
- stdout_json = None
200
- for line in stdout:
201
- try:
202
- stdout_json = json.loads(line)
203
- break
204
- except json.decoder.JSONDecodeError:
205
- stdout_json = None
350
+ with open("wiz_scan.json", "r") as f:
351
+ results = json.load(f)
352
+
353
+ self.logger.debug(results)
206
354
 
207
- if stdout_json is None:
355
+ if results is None:
208
356
  self.logger.error("Failed to parse Wiz CLI output as JSON")
209
- self.logger.debug(stdout)
357
+ self.logger.debug(stdout, results)
210
358
  exit(1)
211
359
 
212
- if "result" not in stdout_json or "ruleMatches" not in stdout_json["result"]:
360
+ if "result" not in results or "ruleMatches" not in results["result"]:
213
361
  self.logger.error("Unexpected Wiz CLI output format")
214
- self.logger.debug(stdout_json)
362
+ self.logger.debug(results)
215
363
  exit(1)
216
364
 
217
- self.add_to_policy_input("wiz", stdout_json)
365
+ self.add_to_policy_input("wiz", results)
218
366
 
219
- if stdout_json["result"]["ruleMatches"] is None:
367
+ if results["result"]["ruleMatches"] is None:
220
368
  self.logger.info("No findings found in the IAC scan.")
221
369
  else:
222
370
  findings = {}
223
371
  # Sort the findings by the severity and their rule id
224
- for match in stdout_json["result"]["ruleMatches"]:
372
+ for match in results["result"]["ruleMatches"]:
225
373
  if match["severity"] not in findings:
226
374
  findings[match["severity"]] = {}
227
375
  if match["rule"]["id"] not in findings[match["severity"]]:
@@ -234,7 +382,7 @@ contexts:
234
382
  )
235
383
 
236
384
  markdown = "# Wiz IAC Scan Findings\n\n"
237
- markdown += f"**Status:** {stdout_json['status']['state']} **Verdict:** {stdout_json['status']['verdict']}\n"
385
+ markdown += f"**Status:** {results['status']['state']} **Verdict:** {results['status']['verdict']}\n"
238
386
  for severity, matches in findings.items():
239
387
  severity = severity.upper()
240
388
 
@@ -260,8 +408,8 @@ contexts:
260
408
  for match in cycled_rule["matches"]:
261
409
  markdown += f"- File: {match['fileName']}, Line: {match['lineNumber']}\n"
262
410
  markdown += "\n"
263
- if "reportUrl" in stdout_json:
264
- markdown += f"[View Report]({stdout_json['reportUrl']})\n"
411
+ if "reportUrl" in results:
412
+ markdown += f"[View Report]({results['reportUrl']})\n"
265
413
  result = self.send_markdown(markdown)
266
414
  if not result:
267
415
  self.logger.error("Failed to send Wiz CLI output to spacelift")
@@ -283,9 +431,9 @@ contexts:
283
431
 
284
432
  ARCH="$(arch)"
285
433
  if [ "$ARCH" = "x86_64" ]; then
286
- URL="https://downloads.wiz.io/wizcli/latest/wizcli-linux-amd64"
434
+ URL="https://downloads.wiz.io/v1/wizcli/latest/wizcli-linux-amd64"
287
435
  elif [ "$ARCH" = "arm64" ] || [ "$ARCH" = "aarch64" ]; then
288
- URL="https://downloads.wiz.io/wizcli/latest/wizcli-linux-arm64"
436
+ URL="https://downloads.wiz.io/v1/wizcli/latest/wizcli-linux-arm64"
289
437
  else
290
438
  echo "Error: Unsupported architecture '$ARCH'"
291
439
  exit 1
@@ -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.3.0'
32
- __version_tuple__ = version_tuple = (1, 3, 0)
31
+ __version__ = version = '1.4.0'
32
+ __version_tuple__ = version_tuple = (1, 4, 0)
33
33
 
34
- __commit_id__ = commit_id = 'gd58f48f7e'
34
+ __commit_id__ = commit_id = 'g6b2d2141a'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spaceforge
3
- Version: 1.3.0
3
+ Version: 1.4.0
4
4
  Summary: A Python framework for building Spacelift plugins
5
5
  Author-email: Spacelift <support@spacelift.io>
6
6
  Maintainer-email: Spacelift <support@spacelift.io>
@@ -1,4 +1,5 @@
1
1
  .gitignore
2
+ CODEOWNERS
2
3
  CONTRIBUTING.md
3
4
  LICENSE
4
5
  MANIFEST.in
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
File without changes