spaceforge 1.1.5__tar.gz → 1.1.6__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 (73) hide show
  1. {spaceforge-1.1.5 → spaceforge-1.1.6}/.github/workflows/ci.yml +37 -5
  2. spaceforge-1.1.5/README.md → spaceforge-1.1.6/CONTRIBUTING.md +101 -268
  3. {spaceforge-1.1.5 → spaceforge-1.1.6}/LICENSE +1 -1
  4. spaceforge-1.1.6/PKG-INFO +56 -0
  5. spaceforge-1.1.6/README.md +15 -0
  6. spaceforge-1.1.6/plugins/checkov/README.md +69 -0
  7. spaceforge-1.1.6/plugins/checkov/plugin.py +346 -0
  8. spaceforge-1.1.6/plugins/checkov/plugin.yaml +445 -0
  9. spaceforge-1.1.6/plugins/checkov/requirements.txt +1 -0
  10. {spaceforge-1.1.5 → spaceforge-1.1.6}/plugins/enviroment_manager/plugin.py +1 -1
  11. {spaceforge-1.1.5 → spaceforge-1.1.6}/plugins/enviroment_manager/plugin.yaml +4 -4
  12. {spaceforge-1.1.5 → spaceforge-1.1.6}/plugins/envsubst/plugin.py +1 -1
  13. {spaceforge-1.1.5 → spaceforge-1.1.6}/plugins/envsubst/plugin.yaml +43 -8
  14. spaceforge-1.1.6/plugins/opentofu-tracing/plugin.py +83 -0
  15. spaceforge-1.1.6/plugins/opentofu-tracing/plugin.yaml +149 -0
  16. {spaceforge-1.1.5 → spaceforge-1.1.6}/plugins/sops/plugin.py +1 -1
  17. {spaceforge-1.1.5 → spaceforge-1.1.6}/plugins/sops/plugin.yaml +45 -10
  18. spaceforge-1.1.6/plugins/terrascan/README.md +50 -0
  19. spaceforge-1.1.6/plugins/terrascan/plugin.py +284 -0
  20. spaceforge-1.1.6/plugins/terrascan/plugin.yaml +432 -0
  21. spaceforge-1.1.6/plugins/trivy/README.md +21 -0
  22. spaceforge-1.1.6/plugins/trivy/plugin.py +224 -0
  23. spaceforge-1.1.6/plugins/trivy/plugin.yaml +389 -0
  24. {spaceforge-1.1.5 → spaceforge-1.1.6}/plugins/wiz/plugin.py +1 -1
  25. {spaceforge-1.1.5 → spaceforge-1.1.6}/plugins/wiz/plugin.yaml +45 -10
  26. spaceforge-1.1.6/regenerate_plugins.sh +81 -0
  27. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/_version_scm.py +3 -3
  28. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/generator.py +6 -2
  29. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/templates/ensure_spaceforge_and_run.sh.j2 +2 -2
  30. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/test_generator.py +2 -2
  31. spaceforge-1.1.6/spaceforge.egg-info/PKG-INFO +56 -0
  32. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge.egg-info/SOURCES.txt +14 -0
  33. spaceforge-1.1.5/PKG-INFO +0 -736
  34. spaceforge-1.1.5/spaceforge.egg-info/PKG-INFO +0 -736
  35. {spaceforge-1.1.5 → spaceforge-1.1.6}/.github/workflows/release.yml +0 -0
  36. {spaceforge-1.1.5 → spaceforge-1.1.6}/.gitignore +0 -0
  37. {spaceforge-1.1.5 → spaceforge-1.1.6}/MANIFEST.in +0 -0
  38. {spaceforge-1.1.5 → spaceforge-1.1.6}/go.mod +0 -0
  39. {spaceforge-1.1.5 → spaceforge-1.1.6}/plugins/enviroment_manager/requirements.txt +0 -0
  40. {spaceforge-1.1.5 → spaceforge-1.1.6}/plugins/infracost/plugin.py +0 -0
  41. {spaceforge-1.1.5 → spaceforge-1.1.6}/plugins/infracost/plugin.yaml +0 -0
  42. {spaceforge-1.1.5 → spaceforge-1.1.6}/plugins/sops/requirements.txt +0 -0
  43. {spaceforge-1.1.5 → spaceforge-1.1.6}/pyproject.toml +0 -0
  44. {spaceforge-1.1.5 → spaceforge-1.1.6}/setup.cfg +0 -0
  45. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/README.md +0 -0
  46. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/__init__.py +0 -0
  47. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/__main__.py +0 -0
  48. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/_version.py +0 -0
  49. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/cls.py +0 -0
  50. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/conftest.py +0 -0
  51. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/plugin.py +0 -0
  52. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/runner.py +0 -0
  53. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/schema.json +0 -0
  54. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/templates/binary_install.sh.j2 +0 -0
  55. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/test_cls.py +0 -0
  56. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/test_generator_binaries.py +0 -0
  57. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/test_generator_core.py +0 -0
  58. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/test_generator_hooks.py +0 -0
  59. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/test_generator_parameters.py +0 -0
  60. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/test_plugin.py +0 -0
  61. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/test_plugin_file_operations.py +0 -0
  62. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/test_plugin_hooks.py +0 -0
  63. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/test_plugin_inheritance.py +0 -0
  64. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/test_runner.py +0 -0
  65. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/test_runner_cli.py +0 -0
  66. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/test_runner_core.py +0 -0
  67. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge/test_runner_execution.py +0 -0
  68. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge.egg-info/dependency_links.txt +0 -0
  69. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge.egg-info/entry_points.txt +0 -0
  70. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge.egg-info/requires.txt +0 -0
  71. {spaceforge-1.1.5 → spaceforge-1.1.6}/spaceforge.egg-info/top_level.txt +0 -0
  72. {spaceforge-1.1.5 → spaceforge-1.1.6}/templates.go +0 -0
  73. {spaceforge-1.1.5 → spaceforge-1.1.6}/test.sh +0 -0
@@ -39,28 +39,60 @@ jobs:
39
39
  run: |
40
40
  ./test.sh
41
41
 
42
+ check-plugin-yaml:
43
+ runs-on: ubuntu-latest
44
+
45
+ steps:
46
+ - uses: actions/checkout@v4
47
+
48
+ - name: Set up Python
49
+ uses: actions/setup-python@v5
50
+ with:
51
+ python-version: '3.11'
52
+
53
+ - name: Install dependencies
54
+ run: |
55
+ python -m pip install --upgrade pip
56
+ pip install -e .
57
+
58
+ - name: Regenerate plugin YAML files
59
+ run: ./regenerate_plugins.sh
60
+
61
+ - name: Check for uncommitted changes
62
+ run: |
63
+ if ! git diff --exit-code; then
64
+ echo "❌ Plugin YAML files are out of date!"
65
+ echo ""
66
+ echo "Please run './regenerate_plugins.sh' and commit the changes."
67
+ echo ""
68
+ echo "Files that need to be updated:"
69
+ git diff --name-only
70
+ exit 1
71
+ fi
72
+ echo "✅ All plugin YAML files are up to date"
73
+
42
74
  build:
43
75
  needs: test
44
76
  runs-on: ubuntu-latest
45
-
77
+
46
78
  steps:
47
79
  - uses: actions/checkout@v4
48
80
  with:
49
81
  fetch-depth: 0 # Fetch full history for setuptools-scm
50
-
82
+
51
83
  - name: Set up Python
52
84
  uses: actions/setup-python@v5
53
85
  with:
54
86
  python-version: '3.11'
55
-
87
+
56
88
  - name: Install build dependencies
57
89
  run: |
58
90
  python -m pip install --upgrade pip
59
91
  pip install build setuptools-scm[toml]
60
-
92
+
61
93
  - name: Build package
62
94
  run: python -m build
63
-
95
+
64
96
  - name: Check distribution
65
97
  run: |
66
98
  pip install twine
@@ -1,18 +1,30 @@
1
- # Spaceforge - Build Spacelift Plugins in Python
1
+ # Spaceforge Contributing Guide
2
2
 
3
- Spaceforge is a Python framework that makes it easy to build powerful Spacelift plugins using a declarative, hook-based approach. Define your plugin logic in Python, and spaceforge automatically generates the plugin manifest for Spacelift.
3
+ ## Reporting an Issue
4
4
 
5
- ## Installation
5
+ If you spot a problem with Spaceforge, [search if an issue already exists](https://github.com/spacelift-io/plugins/issues). If not, please [open a new issue](https://github.com/spacelift-io/plugins/issues/new).
6
6
 
7
- Install spaceforge from PyPI:
7
+ ## Creating a Plugin
8
+
9
+ Creating a plugin involves five steps:
10
+
11
+ 1. **Install spaceforge:** `pip install spaceforge`
12
+ 2. **Create your plugin:** Start with the quick start example.
13
+ 3. **Test locally:** Use the `run` command to test your hooks.
14
+ 4. **Generate manifest:** Use the `generate` command to create plugin.yaml.
15
+ 5. **Upload to Spacelift:** Add your plugin manifest to your Spacelift account.
16
+
17
+ Detailed instructions for each step are below.
18
+
19
+ ### Quick Start
20
+
21
+ #### 1. Install spaceforge
8
22
 
9
23
  ```bash
10
24
  pip install spaceforge
11
25
  ```
12
26
 
13
- ## Quick Start
14
-
15
- ### 1. Create Your Plugin
27
+ #### 2. Create Your Plugin
16
28
 
17
29
  Create a Python file (e.g., `plugin.py`) and inherit from `SpaceforgePlugin`:
18
30
 
@@ -76,17 +88,7 @@ class MyPlugin(SpaceforgePlugin):
76
88
  self.logger.info("Security scan passed!")
77
89
  ```
78
90
 
79
- ### 2. Generate Plugin Manifest
80
-
81
- Generate the Spacelift plugin YAML manifest:
82
-
83
- ```bash
84
- spaceforge generate plugin.py
85
- ```
86
-
87
- This creates `plugin.yaml` that you can upload to Spacelift.
88
-
89
- ### 3. Test Your Plugin
91
+ #### 3. Test Your Plugin
90
92
 
91
93
  Test individual hooks locally:
92
94
 
@@ -99,21 +101,30 @@ export ENVIRONMENT="staging"
99
101
  spaceforge run after_plan
100
102
  ```
101
103
 
102
- ## Available Hooks
104
+ #### 4. Generate Plugin Manifest
103
105
 
104
- Override these methods in your plugin to add custom logic:
106
+ Generate the Spacelift plugin `plugin.yaml` manifest that you can upload to Spacelift.
107
+
108
+ ```bash
109
+ spaceforge generate plugin.py
110
+ ```
105
111
 
106
- - `before_init()` - Before Terraform init
107
- - `after_init()` - After Terraform init
108
- - `before_plan()` - Before Terraform plan
109
- - `after_plan()` - After Terraform plan
110
- - `before_apply()` - Before Terraform apply
111
- - `after_apply()` - After Terraform apply
112
- - `before_perform()` - Before the run performs
113
- - `after_perform()` - After the run performs
114
- - `before_destroy()` - Before Terraform destroy
115
- - `after_destroy()` - After Terraform destroy
116
- - `after_run()` - After the run completes
112
+ #### 5. Upload your Plugin to Spacelift
113
+
114
+ For more advanced examples, see the [plugins](plugins/) directory in this repository.
115
+
116
+ ### Available Hooks
117
+
118
+ Implement these methods in your plugin to add custom logic before and after specific run phases:
119
+
120
+ - **Initialization** (`before_init()` and `after_init()`)
121
+ - **Planning** (`before_plan()` and `after_plan()`)
122
+ - **Applying** (`before_apply()` and `after_apply()`)
123
+ - **Destroying** (`before_destroy()` and `after_destroy()`)
124
+ - Used during module test cases.
125
+ - Used by stacks during destruction with corresponding `stack_destructor_resource`.
126
+ - **Performing** (`before_perform()` and `after_perform()`): Used during stack tasks execution.
127
+ - **Finally** (`after_run()`): Executed after each actively processed run, regardless of its outcome. These hooks have access to an environment variable called `TF_VAR_spacelift_final_run_state`, which indicates the final state of the run.
117
128
 
118
129
  ## Plugin Components
119
130
 
@@ -126,6 +137,27 @@ class MyPlugin(SpaceforgePlugin):
126
137
  __labels__ = ["security", "monitoring", "compliance"]
127
138
  ```
128
139
 
140
+ ### Binaries
141
+
142
+ Automatically download and install external tools:
143
+
144
+ ```python
145
+ __binaries__ = [
146
+ Binary(
147
+ name="kubectl",
148
+ download_urls={
149
+ "amd64": "https://dl.k8s.io/release/v1.28.0/bin/linux/amd64/kubectl",
150
+ "arm64": "https://dl.k8s.io/release/v1.28.0/bin/linux/arm64/kubectl"
151
+ }
152
+ )
153
+ ]
154
+ ```
155
+
156
+ **Notes**:
157
+ - Only open-source-licensed binaries can be used in plugins unless Spacelift has authorized them.
158
+ - `.tar.bz2`, `.tar.gz`, and `.zip` archives are extracted automatically.
159
+ - Archives must contain a file matching the binary name. All other files are ignored.
160
+
129
161
  ### Parameters
130
162
 
131
163
  Define user-configurable parameters:
@@ -149,13 +181,13 @@ __parameters__ = [
149
181
  ]
150
182
  ```
151
183
 
152
- **Parameter Notes:**
153
- - Parameter `name` is displayed in the Spacelift UI
154
- - Parameter `id` (optional) is used for programmatic reference
155
- - `value_from_parameter` can reference either the `id` (if present) or the `name`
156
- - Parameters are made available as environment variables through Variable definitions
157
- - Default values must be strings
158
- - Required parameters cannot have default values
184
+ **Notes:**
185
+ - Parameter `name` is displayed in the Spacelift UI.
186
+ - Parameter `id` (optional) is used for programmatic reference.
187
+ - `value_from_parameter` can reference either the `id` (if present) or the `name`.
188
+ - Parameters are made available as environment variables through Variable definitions.
189
+ - Default values must be strings.
190
+ - Required parameters cannot have default values.
159
191
 
160
192
  ### Contexts
161
193
 
@@ -188,22 +220,6 @@ __contexts__ = [
188
220
  ]
189
221
  ```
190
222
 
191
- ### Binaries
192
-
193
- Automatically download and install external tools:
194
-
195
- ```python
196
- __binaries__ = [
197
- Binary(
198
- name="kubectl",
199
- download_urls={
200
- "amd64": "https://dl.k8s.io/release/v1.28.0/bin/linux/amd64/kubectl",
201
- "arm64": "https://dl.k8s.io/release/v1.28.0/bin/linux/arm64/kubectl"
202
- }
203
- )
204
- ]
205
- ```
206
-
207
223
  **Context Priority System:**
208
224
 
209
225
  Control the execution order of contexts using the `priority` field:
@@ -229,13 +245,13 @@ __contexts__ = [
229
245
  ]
230
246
  ```
231
247
 
232
- **Priority Notes:**
233
- - Default priority is `0`
234
- - Lower numbers execute first (0, then 1, then 2, etc.)
235
- - Useful for ensuring setup contexts run before main execution contexts
248
+ **Notes:**
249
+ - Default priority is `0`.
250
+ - Lower numbers execute first (0, then 1, then 2, etc.).
251
+ - Useful for ensuring setup contexts run before main execution contexts.
236
252
 
237
253
  **Binary PATH Management:**
238
- - When using Python hook methods (e.g., `def before_apply()`), binaries are automatically available in PATH
254
+ - When using Python hook methods (e.g., `def before_apply()`), binaries are automatically available in `$PATH`.
239
255
  - When using raw context hooks, you must manually export the PATH:
240
256
 
241
257
  ```python
@@ -280,11 +296,11 @@ __contexts__ = [
280
296
  ]
281
297
  ```
282
298
 
283
- **MountedFile Notes:**
284
- - Files are created at the specified path when the context is applied
285
- - Content is written exactly as provided
286
- - Use `sensitive=True` for files containing secrets or sensitive data
287
- - path is from `/mnt/workspace/`. An example would be `tmp/config.json` which would be mounted at `/mnt/workspace/tmp/config.json`
299
+ **Notes:**
300
+ - Files are created at the specified path when the context is applied.
301
+ - Content is written exactly as provided.
302
+ - Use `sensitive=True` for files containing secrets or sensitive data.
303
+ - path is from `/mnt/workspace/`. An example would be `tmp/config.json` which would be mounted at `/mnt/workspace/tmp/config.json`.
288
304
 
289
305
  ### Policies
290
306
 
@@ -398,11 +414,11 @@ def before_plan(self):
398
414
  self.logger.info(f"Authenticated as: {result['viewer']['login']}")
399
415
  ```
400
416
 
401
- **User Token Notes:**
402
- - Allows plugins to act on behalf of a specific user
403
- - Useful for operations requiring user-specific permissions
404
- - User tokens may have different access levels than service tokens
405
- - Call `use_user_token()` before making API requests
417
+ **Notes:**
418
+ - Allows plugins to act on behalf of a specific user.
419
+ - Useful for operations requiring user-specific permissions.
420
+ - User tokens may have different access levels than service tokens.
421
+ - Call `use_user_token()` before making API requests.
406
422
 
407
423
  ### Access Plan and State
408
424
 
@@ -423,7 +439,7 @@ def after_plan(self):
423
439
 
424
440
  ### Send Rich Output
425
441
 
426
- Send formatted markdown to the Spacelift UI:
442
+ Send formatted Markdown to the Spacelift UI:
427
443
 
428
444
  ```python
429
445
  def after_plan(self):
@@ -442,8 +458,6 @@ def after_plan(self):
442
458
 
443
459
  ### Add to Policy Input
444
460
 
445
- Add custom data to the OPA policy input:
446
-
447
461
  The following example will create input available via `input.third_party_metadata.custom.my_custom_data` in your OPA policies:
448
462
  ```python
449
463
  def after_plan(self):
@@ -455,44 +469,9 @@ def after_plan(self):
455
469
  })
456
470
  ```
457
471
 
458
- ## CLI Commands
459
-
460
- ### Generate Plugin Manifest
461
-
462
- ```bash
463
- # Generate from plugin.py (default filename)
464
- spaceforge generate
465
-
466
- # Generate from specific file
467
- spaceforge generate my_plugin.py
468
-
469
- # Specify output file
470
- spaceforge generate my_plugin.py -o custom-output.yaml
471
-
472
- # Get help
473
- spaceforge generate --help
474
- ```
475
-
476
- ### Test Plugin Hooks
477
-
478
- ```bash
479
- # Set parameters for local testing (parameters are normally provided by Spacelift)
480
- export API_KEY="test-key"
481
- export TIMEOUT="60"
482
-
483
- # Test specific hook
484
- spaceforge run after_plan
485
-
486
- # Test with specific plugin file
487
- spaceforge run --plugin-file my_plugin.py before_apply
488
-
489
- # Get help
490
- spaceforge run --help
491
- ```
492
-
493
472
  ## Plugin Development Tips
494
473
 
495
- ### 1. Handle Dependencies
474
+ ### Handle Dependencies
496
475
 
497
476
  If your plugin needs Python packages, create a `requirements.txt` file. Spaceforge automatically adds a `before_init` hook to install them:
498
477
 
@@ -512,7 +491,7 @@ def after_plan(self):
512
491
  self.logger.info(f"Processing run {run_id} for stack {stack_id}")
513
492
  ```
514
493
 
515
- ### 3. Error Handling
494
+ ### Error Handling
516
495
 
517
496
  Always handle errors gracefully:
518
497
 
@@ -528,168 +507,22 @@ def after_plan(self):
528
507
  exit(1)
529
508
  ```
530
509
 
531
- ### 4. Testing and Debugging
510
+ ### Testing and Debugging
532
511
 
533
- - Set `SPACELIFT_DEBUG=true` to enable debug logging
534
- - Use the `run` command to test hooks during development
535
- - Test with different parameter combinations
536
- - Validate your generated YAML before uploading to Spacelift
512
+ - Set `SPACELIFT_DEBUG=true` to enable debug logging.
513
+ - Use the `run` command to test hooks during development.
514
+ - Test with different parameter combinations.
515
+ - Validate your generated YAML before uploading to Spacelift.
537
516
 
538
- ## Example: Security Scanning Plugin
517
+ ### Speeding Up Plugin Execution
539
518
 
540
- Here's a complete example of a security scanning plugin:
519
+ There are a few things you can do to speed up plugin execution:
541
520
 
542
- ```python
543
- import os
544
- import json
545
- from spaceforge import SpaceforgePlugin, Parameter, Variable, Context, Binary, Policy, MountedFile
521
+ - Ensure your runner has `spaceforge` preinstalled. This will avoid the overhead of installing it during the run. (15-30 seconds)
522
+ - If you use binaries, we will only install the binary if its not found. You can gain a few seconds by ensuring its already on the runner.
523
+ - If your plugin has a lot of dependencies, consider using a prebuilt runner image with your plugin and its dependencies installed. This avoids the overhead of installing them during each run.
524
+ - Ensure your runner has enough core resources (CPU, memory) to handle the plugin execution efficiently. If your plugin is resource-intensive, consider using a more powerful runner.
546
525
 
547
- class SecurityScannerPlugin(SpaceforgePlugin):
548
- __plugin_name__ = "security-scanner"
549
- __version__ = "1.0.0"
550
- __author__ = "Security Team"
551
-
552
- __binaries__ = [
553
- Binary(
554
- name="security-cli",
555
- download_urls={
556
- "amd64": "https://releases.example.com/security-cli-linux-amd64",
557
- "arm64": "https://releases.example.com/security-cli-linux-arm64"
558
- }
559
- )
560
- ]
561
-
562
- __parameters__ = [
563
- Parameter(
564
- name="API Token",
565
- id="api_token",
566
- description="Security service API token",
567
- required=True,
568
- sensitive=True
569
- ),
570
- Parameter(
571
- name="Severity Threshold",
572
- id="severity_threshold",
573
- description="Minimum severity level to report",
574
- required=False,
575
- default="medium"
576
- )
577
- ]
578
-
579
- __contexts__ = [
580
- Context(
581
- name_prefix="security-scanner",
582
- description="Security scanning context",
583
- env=[
584
- Variable(
585
- key="SECURITY_API_TOKEN",
586
- value_from_parameter="api_token",
587
- sensitive=True
588
- ),
589
- Variable(
590
- key="SEVERITY_THRESHOLD",
591
- value_from_parameter="severity_threshold"
592
- )
593
- ]
594
- )
595
- ]
596
-
597
- def after_plan(self):
598
- """Run security scan after Terraform plan"""
599
- self.logger.info("Starting security scan of Terraform plan")
600
-
601
- # Authenticate with security service
602
- return_code, stdout, stderr = self.run_cli(
603
- "security-cli", "auth",
604
- "--token", os.environ["SECURITY_API_TOKEN"]
605
- )
606
-
607
- if return_code != 0:
608
- self.logger.error("Failed to authenticate with security service")
609
- exit(1)
610
-
611
- # Scan the Terraform plan
612
- return_code, stdout, stderr = self.run_cli(
613
- "security-cli", "scan", "terraform",
614
- "--plan-file", "spacelift.plan.json",
615
- "--format", "json",
616
- "--severity", os.environ.get("SEVERITY_THRESHOLD", "medium"),
617
- print_output=False
618
- )
619
-
620
- if return_code != 0:
621
- self.logger.error("Security scan failed")
622
- for line in stderr:
623
- self.logger.error(line)
624
- exit(1)
625
-
626
- # Parse scan results
627
- try:
628
- results = json.loads('\n'.join(stdout))
629
-
630
- # Generate markdown report
631
- markdown = self._generate_report(results)
632
- self.send_markdown(markdown)
633
-
634
- # Fail run if critical issues found
635
- if results.get('critical_count', 0) > 0:
636
- self.logger.error(f"Found {results['critical_count']} critical security issues")
637
- exit(1)
638
-
639
- self.logger.info("Security scan completed successfully")
640
-
641
- except json.JSONDecodeError:
642
- self.logger.error("Failed to parse scan results")
643
- exit(1)
644
-
645
- def _generate_report(self, results):
646
- """Generate markdown report from scan results"""
647
- report = "# Security Scan Results\n\n"
648
-
649
- if results.get('total_issues', 0) == 0:
650
- report += "✅ **No security issues found!**\n"
651
- else:
652
- report += f"Found {results['total_issues']} security issues:\n\n"
653
-
654
- for severity in ['critical', 'high', 'medium', 'low']:
655
- count = results.get(f'{severity}_count', 0)
656
- if count > 0:
657
- emoji = {'critical': '🔴', 'high': '🟠', 'medium': '🟡', 'low': '🟢'}[severity]
658
- report += f"- {emoji} **{severity.upper()}:** {count}\n"
659
-
660
- if results.get('report_url'):
661
- report += f"\n[View detailed report]({results['report_url']})\n"
662
-
663
- return report
664
- ```
665
-
666
- Generate and test this plugin:
526
+ ## Working on Spaceforge
667
527
 
668
- ```bash
669
- # Generate the manifest
670
- spaceforge generate security_scanner.py
671
-
672
- # Test locally
673
- export API_TOKEN="your-token"
674
- export SEVERITY_THRESHOLD="high"
675
- spaceforge run after_plan
676
- ```
677
-
678
- ## Speeding up plugin execution
679
-
680
- There are a few things you can do to speed up plugin execution.
681
-
682
- 1. Ensure your runner has `spaceforge` preinstalled. This will avoid the overhead of installing it during the run. (15-30 seconds)
683
- 2. If youre using binaries, we will only install the binary if its not found. You can gain a few seconds by ensuring its already on the runner.
684
- 3. If your plugin has a lot of dependencies, consider using a prebuilt runner image with your plugin and its dependencies installed. This avoids the overhead of installing them during each run.
685
- 4. Ensure your runner has enough core resources (CPU, memory) to handle the plugin execution efficiently. If your plugin is resource-intensive, consider using a more powerful runner.
686
-
687
- ## Next Steps
688
-
689
- 1. **Install spaceforge:** `pip install spaceforge`
690
- 2. **Create your plugin:** Start with the quick start example
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
- 5. **Upload to Spacelift:** Add your plugin manifest to your Spacelift account
694
-
695
- For more advanced examples, see the [plugins](plugins/) directory in this repository.
528
+ See the [README file](./spaceforge/README.md) in the `spaceforge` folder.
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 Spacelift
3
+ Copyright (c) 2025 Spacelift
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,56 @@
1
+ Metadata-Version: 2.4
2
+ Name: spaceforge
3
+ Version: 1.1.6
4
+ Summary: A Python framework for building Spacelift plugins
5
+ Author-email: Spacelift <support@spacelift.io>
6
+ Maintainer-email: Spacelift <support@spacelift.io>
7
+ License: MIT
8
+ Project-URL: Homepage, https://github.com/spacelift-io/plugins
9
+ Project-URL: Documentation, https://github.com/spacelift-io/plugins#readme
10
+ Project-URL: Repository, https://github.com/spacelift-io/plugins
11
+ Project-URL: Bug Reports, https://github.com/spacelift-io/plugins/issues
12
+ Keywords: spacelift,plugin,framework,infrastructure,devops,spaceforge
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: System :: Systems Administration
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: PyYAML>=6.0
27
+ Requires-Dist: click>=8.0.0
28
+ Requires-Dist: pydantic>=2.11.7
29
+ Requires-Dist: Jinja2>=3.1.0
30
+ Requires-Dist: mergedeep>=1.3.4
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=6.0; extra == "dev"
33
+ Requires-Dist: pytest-cov; extra == "dev"
34
+ Requires-Dist: black; extra == "dev"
35
+ Requires-Dist: isort; extra == "dev"
36
+ Requires-Dist: mypy; extra == "dev"
37
+ Requires-Dist: types-PyYAML; extra == "dev"
38
+ Requires-Dist: setuptools-scm[toml]>=6.2; extra == "dev"
39
+ Requires-Dist: autoflake; extra == "dev"
40
+ Dynamic: license-file
41
+
42
+ # Spaceforge - Build Spacelift Plugins in Python
43
+
44
+ Spaceforge is a Python framework for building powerful Spacelift plugins using a declarative, hook-based approach. Define your plugin logic in Python, and Spaceforge automatically generates the plugin manifest for Spacelift.
45
+
46
+ ## Usage
47
+
48
+ For installation and usage instructions, see [our documentation](https://docs.spacelift.io/integrations/plugins).
49
+
50
+ ## Contributing
51
+
52
+ To contribute to Spaceforge or create plugins, see our [CONTRIBUTING.md](./CONTRIBUTING.md) file.
53
+
54
+ ## License
55
+
56
+ Spaceforge and Spacelift plugins are licensed under the [MIT license](./LICENSE).
@@ -0,0 +1,15 @@
1
+ # Spaceforge - Build Spacelift Plugins in Python
2
+
3
+ Spaceforge is a Python framework for building powerful Spacelift plugins using a declarative, hook-based approach. Define your plugin logic in Python, and Spaceforge automatically generates the plugin manifest for Spacelift.
4
+
5
+ ## Usage
6
+
7
+ For installation and usage instructions, see [our documentation](https://docs.spacelift.io/integrations/plugins).
8
+
9
+ ## Contributing
10
+
11
+ To contribute to Spaceforge or create plugins, see our [CONTRIBUTING.md](./CONTRIBUTING.md) file.
12
+
13
+ ## License
14
+
15
+ Spaceforge and Spacelift plugins are licensed under the [MIT license](./LICENSE).