diff --git a/.changeset/healthy-dots-ring.md b/.changeset/healthy-dots-ring.md
new file mode 100644
index 0000000000..005e7e6616
--- /dev/null
+++ b/.changeset/healthy-dots-ring.md
@@ -0,0 +1,6 @@
+---
+'@backstage/plugin-scaffolder-backend': patch
+'@backstage/plugin-scaffolder-node': patch
+---
+
+Scaffolder workspace serialization
diff --git a/.github/workflows/api-breaking-changes-comment.yml b/.github/workflows/api-breaking-changes-comment.yml
index bc90a276f0..9ae32e1d4a 100644
--- a/.github/workflows/api-breaking-changes-comment.yml
+++ b/.github/workflows/api-breaking-changes-comment.yml
@@ -22,7 +22,7 @@ jobs:
action: ${{ steps.event.outputs.ACTION }}
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
disable-sudo: true
egress-policy: block
diff --git a/.github/workflows/api-breaking-changes.yml b/.github/workflows/api-breaking-changes.yml
index ef09fa10ae..84161e3010 100644
--- a/.github/workflows/api-breaking-changes.yml
+++ b/.github/workflows/api-breaking-changes.yml
@@ -14,7 +14,7 @@ jobs:
if: ${{ github.event_name != 'pull_request' || github.event.action != 'closed' }}
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/automate_area-labels.yml b/.github/workflows/automate_area-labels.yml
index 632624bd50..74f577f360 100644
--- a/.github/workflows/automate_area-labels.yml
+++ b/.github/workflows/automate_area-labels.yml
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/automate_changeset_feedback.yml b/.github/workflows/automate_changeset_feedback.yml
index fefc73bd9f..ef1a258239 100644
--- a/.github/workflows/automate_changeset_feedback.yml
+++ b/.github/workflows/automate_changeset_feedback.yml
@@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/automate_merge_message.yml b/.github/workflows/automate_merge_message.yml
index d6520d16a6..dd8895a752 100644
--- a/.github/workflows/automate_merge_message.yml
+++ b/.github/workflows/automate_merge_message.yml
@@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/automate_stale.yml b/.github/workflows/automate_stale.yml
index c7674e853d..afb8f3b838 100644
--- a/.github/workflows/automate_stale.yml
+++ b/.github/workflows/automate_stale.yml
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/ci-noop.yml b/.github/workflows/ci-noop.yml
index 2c66da768f..4dc8594bc9 100644
--- a/.github/workflows/ci-noop.yml
+++ b/.github/workflows/ci-noop.yml
@@ -40,7 +40,7 @@ jobs:
name: Test ${{ matrix.node-version }}
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c819ae8130..c538ec8957 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -28,7 +28,7 @@ jobs:
name: Install ${{ matrix.node-version }}
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
@@ -64,7 +64,7 @@ jobs:
name: Verify ${{ matrix.node-version }}
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml
index c32d50ced5..7dcb4a9c0f 100644
--- a/.github/workflows/cron.yml
+++ b/.github/workflows/cron.yml
@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/deploy_docker-image.yml b/.github/workflows/deploy_docker-image.yml
index 8c263fdd4f..d5f5eee35e 100644
--- a/.github/workflows/deploy_docker-image.yml
+++ b/.github/workflows/deploy_docker-image.yml
@@ -20,7 +20,7 @@ jobs:
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/deploy_microsite.yml b/.github/workflows/deploy_microsite.yml
index b955b39b59..037fb27e8d 100644
--- a/.github/workflows/deploy_microsite.yml
+++ b/.github/workflows/deploy_microsite.yml
@@ -24,7 +24,7 @@ jobs:
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/deploy_nightly.yml b/.github/workflows/deploy_nightly.yml
index a3a1b5e283..ab8ea3c773 100644
--- a/.github/workflows/deploy_nightly.yml
+++ b/.github/workflows/deploy_nightly.yml
@@ -15,7 +15,7 @@ jobs:
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/deploy_packages.yml b/.github/workflows/deploy_packages.yml
index 0c44d32384..44222275ad 100644
--- a/.github/workflows/deploy_packages.yml
+++ b/.github/workflows/deploy_packages.yml
@@ -144,7 +144,7 @@ jobs:
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/issue.yaml b/.github/workflows/issue.yaml
index f8f5efacc4..7afc0a81bb 100644
--- a/.github/workflows/issue.yaml
+++ b/.github/workflows/issue.yaml
@@ -10,7 +10,7 @@ jobs:
if: github.repository == 'backstage/backstage'
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/pr-review-comment-trigger.yaml b/.github/workflows/pr-review-comment-trigger.yaml
index 5e7d71cbf4..bea1618608 100644
--- a/.github/workflows/pr-review-comment-trigger.yaml
+++ b/.github/workflows/pr-review-comment-trigger.yaml
@@ -20,7 +20,7 @@ jobs:
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/pr-review-comment.yaml b/.github/workflows/pr-review-comment.yaml
index 72256a8c6e..232089e2f3 100644
--- a/.github/workflows/pr-review-comment.yaml
+++ b/.github/workflows/pr-review-comment.yaml
@@ -17,7 +17,7 @@ jobs:
steps:
# Inspired by https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#using-data-from-the-triggering-workflow
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml
index 3aa20b1c96..779137b52a 100644
--- a/.github/workflows/pr.yaml
+++ b/.github/workflows/pr.yaml
@@ -18,7 +18,7 @@ jobs:
if: github.repository == 'backstage/backstage' && ( github.event.pull_request || github.event.issue.pull_request )
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml
index 3c36cae863..8a069d476d 100644
--- a/.github/workflows/scorecard.yml
+++ b/.github/workflows/scorecard.yml
@@ -29,7 +29,7 @@ jobs:
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/sync_code-formatting.yml b/.github/workflows/sync_code-formatting.yml
index a59eea9c9b..7f10ae60df 100644
--- a/.github/workflows/sync_code-formatting.yml
+++ b/.github/workflows/sync_code-formatting.yml
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/sync_dependabot-changesets.yml b/.github/workflows/sync_dependabot-changesets.yml
index 88997ea5dd..7c8e634fb8 100644
--- a/.github/workflows/sync_dependabot-changesets.yml
+++ b/.github/workflows/sync_dependabot-changesets.yml
@@ -11,7 +11,7 @@ jobs:
if: github.actor == 'dependabot[bot]' && github.repository == 'backstage/backstage'
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/sync_release-manifest.yml b/.github/workflows/sync_release-manifest.yml
index 1549ec0e90..7fe8817731 100644
--- a/.github/workflows/sync_release-manifest.yml
+++ b/.github/workflows/sync_release-manifest.yml
@@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/sync_renovate-changesets.yml b/.github/workflows/sync_renovate-changesets.yml
index e95a68ac2f..e1c5656d08 100644
--- a/.github/workflows/sync_renovate-changesets.yml
+++ b/.github/workflows/sync_renovate-changesets.yml
@@ -11,7 +11,7 @@ jobs:
if: github.actor == 'renovate[bot]' && github.repository == 'backstage/backstage'
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/sync_snyk-github-issues.yml b/.github/workflows/sync_snyk-github-issues.yml
index bebbbc4fbe..1948807215 100644
--- a/.github/workflows/sync_snyk-github-issues.yml
+++ b/.github/workflows/sync_snyk-github-issues.yml
@@ -12,7 +12,7 @@ jobs:
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/sync_snyk-monitor.yml b/.github/workflows/sync_snyk-monitor.yml
index cb3efcfac3..43c613b641 100644
--- a/.github/workflows/sync_snyk-monitor.yml
+++ b/.github/workflows/sync_snyk-monitor.yml
@@ -25,7 +25,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/sync_version-packages.yml b/.github/workflows/sync_version-packages.yml
index 82a0eae7be..ed69fd3c24 100644
--- a/.github/workflows/sync_version-packages.yml
+++ b/.github/workflows/sync_version-packages.yml
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/uffizzi-build.yml b/.github/workflows/uffizzi-build.yml
index 1a742bdf24..eab0a61e46 100644
--- a/.github/workflows/uffizzi-build.yml
+++ b/.github/workflows/uffizzi-build.yml
@@ -26,7 +26,7 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
@@ -84,7 +84,7 @@ jobs:
- build-backstage
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
@@ -118,7 +118,7 @@ jobs:
if: ${{ github.event.action == 'closed' }}
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/uffizzi-preview.yaml b/.github/workflows/uffizzi-preview.yaml
index b4c5aa3caa..8d0f558b1f 100644
--- a/.github/workflows/uffizzi-preview.yaml
+++ b/.github/workflows/uffizzi-preview.yaml
@@ -23,7 +23,7 @@ jobs:
action: ${{ steps.event.outputs.ACTION }}
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
disable-sudo: true
egress-policy: block
diff --git a/.github/workflows/verify_accessibility-noop.yml b/.github/workflows/verify_accessibility-noop.yml
index 07c92b5b5d..7ec67cbf0f 100644
--- a/.github/workflows/verify_accessibility-noop.yml
+++ b/.github/workflows/verify_accessibility-noop.yml
@@ -26,7 +26,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_accessibility.yml b/.github/workflows/verify_accessibility.yml
index b4615fee0a..2c0e10c118 100644
--- a/.github/workflows/verify_accessibility.yml
+++ b/.github/workflows/verify_accessibility.yml
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_codeql.yml b/.github/workflows/verify_codeql.yml
index 60cb89a045..f028147b85 100644
--- a/.github/workflows/verify_codeql.yml
+++ b/.github/workflows/verify_codeql.yml
@@ -42,7 +42,7 @@ jobs:
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_docs-quality.yml b/.github/workflows/verify_docs-quality.yml
index 2eb7608ccd..21d3563b57 100644
--- a/.github/workflows/verify_docs-quality.yml
+++ b/.github/workflows/verify_docs-quality.yml
@@ -12,7 +12,7 @@ jobs:
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_e2e-kubernetes-noop.yml b/.github/workflows/verify_e2e-kubernetes-noop.yml
index 8d8b14d5ba..6352abce70 100644
--- a/.github/workflows/verify_e2e-kubernetes-noop.yml
+++ b/.github/workflows/verify_e2e-kubernetes-noop.yml
@@ -23,7 +23,7 @@ jobs:
name: Kubernetes ${{ matrix.node-version }}
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_e2e-kubernetes.yml b/.github/workflows/verify_e2e-kubernetes.yml
index 3c425c25e9..ffaa7971e6 100644
--- a/.github/workflows/verify_e2e-kubernetes.yml
+++ b/.github/workflows/verify_e2e-kubernetes.yml
@@ -22,7 +22,7 @@ jobs:
name: Kubernetes ${{ matrix.node-version }}
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_e2e-linux-noop.yml b/.github/workflows/verify_e2e-linux-noop.yml
index 93d48caf22..2b7eb1d84b 100644
--- a/.github/workflows/verify_e2e-linux-noop.yml
+++ b/.github/workflows/verify_e2e-linux-noop.yml
@@ -29,7 +29,7 @@ jobs:
name: E2E Linux ${{ matrix.node-version }}
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_e2e-linux.yml b/.github/workflows/verify_e2e-linux.yml
index 75c7a800d8..6ff3b9eecf 100644
--- a/.github/workflows/verify_e2e-linux.yml
+++ b/.github/workflows/verify_e2e-linux.yml
@@ -41,7 +41,7 @@ jobs:
name: E2E Linux ${{ matrix.node-version }}
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_e2e-techdocs.yml b/.github/workflows/verify_e2e-techdocs.yml
index d5f2594285..ad0950392f 100644
--- a/.github/workflows/verify_e2e-techdocs.yml
+++ b/.github/workflows/verify_e2e-techdocs.yml
@@ -30,7 +30,7 @@ jobs:
name: Techdocs
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_e2e-windows-noop.yml b/.github/workflows/verify_e2e-windows-noop.yml
index a7ebdba4b5..fd90b86b0d 100644
--- a/.github/workflows/verify_e2e-windows-noop.yml
+++ b/.github/workflows/verify_e2e-windows-noop.yml
@@ -25,7 +25,7 @@ jobs:
name: E2E Windows ${{ matrix.node-version }}
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_e2e-windows.yml b/.github/workflows/verify_e2e-windows.yml
index a6fa469666..7a823a85e1 100644
--- a/.github/workflows/verify_e2e-windows.yml
+++ b/.github/workflows/verify_e2e-windows.yml
@@ -31,7 +31,7 @@ jobs:
name: E2E Windows ${{ matrix.node-version }}
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_fossa.yml b/.github/workflows/verify_fossa.yml
index ccc9e4509a..4c9b1516a2 100644
--- a/.github/workflows/verify_fossa.yml
+++ b/.github/workflows/verify_fossa.yml
@@ -14,7 +14,7 @@ jobs:
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_microsite-noop.yml b/.github/workflows/verify_microsite-noop.yml
index ad3e67ba70..a9a82b140b 100644
--- a/.github/workflows/verify_microsite-noop.yml
+++ b/.github/workflows/verify_microsite-noop.yml
@@ -21,7 +21,7 @@ jobs:
name: Microsite
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_microsite.yml b/.github/workflows/verify_microsite.yml
index d5cda46253..724fac7fef 100644
--- a/.github/workflows/verify_microsite.yml
+++ b/.github/workflows/verify_microsite.yml
@@ -24,7 +24,7 @@ jobs:
name: Microsite
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_microsite_accessibility-noop.yml b/.github/workflows/verify_microsite_accessibility-noop.yml
index 4b63dc41cc..8ac2672b22 100644
--- a/.github/workflows/verify_microsite_accessibility-noop.yml
+++ b/.github/workflows/verify_microsite_accessibility-noop.yml
@@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_microsite_accessibility.yml b/.github/workflows/verify_microsite_accessibility.yml
index 19417c5cee..af2364e743 100644
--- a/.github/workflows/verify_microsite_accessibility.yml
+++ b/.github/workflows/verify_microsite_accessibility.yml
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_storybook-noop.yml b/.github/workflows/verify_storybook-noop.yml
index 74aed57f5c..e98da4ae02 100644
--- a/.github/workflows/verify_storybook-noop.yml
+++ b/.github/workflows/verify_storybook-noop.yml
@@ -28,7 +28,7 @@ jobs:
name: Storybook
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_storybook.yml b/.github/workflows/verify_storybook.yml
index 6a37f5abb6..3cdb0de344 100644
--- a/.github/workflows/verify_storybook.yml
+++ b/.github/workflows/verify_storybook.yml
@@ -28,7 +28,7 @@ jobs:
name: Storybook
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/.github/workflows/verify_windows.yml b/.github/workflows/verify_windows.yml
index c7ff8f5ca9..0c54cfb287 100644
--- a/.github/workflows/verify_windows.yml
+++ b/.github/workflows/verify_windows.yml
@@ -29,7 +29,7 @@ jobs:
steps:
- name: Harden Runner
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit
diff --git a/ADOPTERS.md b/ADOPTERS.md
index 7c4d3566a5..4a6f726fcd 100644
--- a/ADOPTERS.md
+++ b/ADOPTERS.md
@@ -268,4 +268,5 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/
| [Aurora Innovation](https://aurorainnovation.com) | [@O5ten](https://github.com/O5ten) | Heavy usage of scaffolder, techdocs, homepage, k8s plugin and homegrown plugins to track migration paths and so on within a developer portal. It acts as a starting point for new and old developers to find all of our internal tooling in one place.
| [ENSEK](https://ensek.com/) | [Timothy Deakin](https://github.com/cftad) |We are using Backstage as our internal developer portal to provide a single pane of glass for our developers to access all the tools and services they need to build and maintain our software. |
| [OP Financial Group](https://www.op.fi/op-financial-group) | [Heikki Hellgren](https://github.com/drodil), [Jyrki Koistinen](https://github.com/snyvision) | We are using Backstage as a gateway into our internal development platform offering to simplify complexity. |
+| [Scania](https://www.scania.com) | [Santosh Rangavajjula](https://linkedin.com/in/rsbth) | We are implementing backstage at Scania to consolidate operational information from Gitlab, Jira, Confluence, Artifactory, Servicenow and other tools into one place. |
| [Senora.dev](https://senora.dev) | [Shaked Braimok Yosef](https://github.com/ShakedBraimok) | We are using Backstage as a service catalog for our costumers. |
diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md
index 9de99c7a5b..895b55f6e1 100644
--- a/plugins/scaffolder-backend/api-report.md
+++ b/plugins/scaffolder-backend/api-report.md
@@ -3,6 +3,8 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
+///
+
import { ActionContext as ActionContext_2 } from '@backstage/plugin-scaffolder-node';
import { AuthService } from '@backstage/backend-plugin-api';
import * as azure from '@backstage/plugin-scaffolder-backend-module-azure';
@@ -370,6 +372,8 @@ export interface CurrentClaimedTask {
spec: TaskSpec;
state?: JsonObject;
taskId: string;
+ // (undocumented)
+ workspace?: Promise;
}
// @public
@@ -385,6 +389,8 @@ export class DatabaseTaskStore implements TaskStore {
// (undocumented)
claimTask(): Promise;
// (undocumented)
+ cleanWorkspace({ taskId }: { taskId: string }): Promise;
+ // (undocumented)
completeTask(options: {
taskId: string;
status: TaskStatus_2;
@@ -435,8 +441,15 @@ export class DatabaseTaskStore implements TaskStore {
ids: string[];
}>;
// (undocumented)
+ rehydrateWorkspace(options: {
+ taskId: string;
+ targetPath: string;
+ }): Promise;
+ // (undocumented)
saveTaskState(options: { taskId: string; state?: JsonObject }): Promise;
// (undocumented)
+ serializeWorkspace(options: { path: string; taskId: string }): Promise;
+ // (undocumented)
shutdownTask(options: TaskStoreShutDownTaskOptions): Promise;
}
@@ -529,6 +542,8 @@ export class TaskManager implements TaskContext_2 {
// (undocumented)
get cancelSignal(): AbortSignal;
// (undocumented)
+ cleanWorkspace?(): Promise;
+ // (undocumented)
complete(result: TaskCompletionState_2, metadata?: JsonObject): Promise;
// (undocumented)
static create(
@@ -537,6 +552,7 @@ export class TaskManager implements TaskContext_2 {
abortSignal: AbortSignal,
logger: Logger,
auth?: AuthService,
+ config?: Config,
): TaskManager;
// (undocumented)
get createdBy(): string | undefined;
@@ -556,8 +572,15 @@ export class TaskManager implements TaskContext_2 {
// (undocumented)
getWorkspaceName(): Promise;
// (undocumented)
+ rehydrateWorkspace?(options: {
+ taskId: string;
+ targetPath: string;
+ }): Promise;
+ // (undocumented)
get secrets(): TaskSecrets_2 | undefined;
// (undocumented)
+ serializeWorkspace?(options: { path: string }): Promise;
+ // (undocumented)
get spec(): TaskSpecV1beta3;
// (undocumented)
updateCheckpoint?(
@@ -588,6 +611,8 @@ export interface TaskStore {
// (undocumented)
claimTask(): Promise;
// (undocumented)
+ cleanWorkspace?({ taskId }: { taskId: string }): Promise;
+ // (undocumented)
completeTask(options: {
taskId: string;
status: TaskStatus;
@@ -629,11 +654,24 @@ export interface TaskStore {
ids: string[];
}>;
// (undocumented)
+ rehydrateWorkspace?(options: {
+ taskId: string;
+ targetPath: string;
+ }): Promise;
+ // (undocumented)
saveTaskState?(options: {
taskId: string;
state?: JsonObject;
}): Promise;
// (undocumented)
+ serializeWorkspace?({
+ path,
+ taskId,
+ }: {
+ path: string;
+ taskId: string;
+ }): Promise;
+ // (undocumented)
shutdownTask?(options: TaskStoreShutDownTaskOptions): Promise;
}
diff --git a/plugins/scaffolder-backend/config.d.ts b/plugins/scaffolder-backend/config.d.ts
index 477defe026..754eedb55b 100644
--- a/plugins/scaffolder-backend/config.d.ts
+++ b/plugins/scaffolder-backend/config.d.ts
@@ -47,6 +47,11 @@ export interface Config {
*/
EXPERIMENTAL_recoverTasks?: boolean;
+ /**
+ * Sets the serialization of the workspace to have an ability to rerun the failed task.
+ */
+ EXPERIMENTAL_workspaceSerialization?: boolean;
+
/**
* Every task which is in progress state and having a last heartbeat longer than a specified timeout is going to
* be attempted to recover.
diff --git a/plugins/scaffolder-backend/migrations/20240401213200_workspace.js b/plugins/scaffolder-backend/migrations/20240401213200_workspace.js
new file mode 100644
index 0000000000..175de54cd9
--- /dev/null
+++ b/plugins/scaffolder-backend/migrations/20240401213200_workspace.js
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// @ts-check
+
+/**
+ * @param {import('knex').Knex} knex
+ */
+exports.up = async function up(knex) {
+ await knex.schema.alterTable('tasks', table => {
+ table.binary('workspace').nullable().comment('A snapshot of the workspace');
+ });
+};
+
+/**
+ * @param {import('knex').Knex} knex
+ */
+exports.down = async function down(knex) {
+ await knex.schema.alterTable('tasks', table => {
+ table.dropColumn('workspace');
+ });
+};
diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json
index 338dc290e1..3492901386 100644
--- a/plugins/scaffolder-backend/package.json
+++ b/plugins/scaffolder-backend/package.json
@@ -78,6 +78,7 @@
"@backstage/types": "workspace:^",
"@types/express": "^4.17.6",
"@types/luxon": "^3.0.0",
+ "concat-stream": "^2.0.0",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"fs-extra": "^11.2.0",
@@ -93,6 +94,7 @@
"p-limit": "^3.1.0",
"p-queue": "^6.6.2",
"prom-client": "^15.0.0",
+ "tar": "^6.1.12",
"uuid": "^9.0.0",
"winston": "^3.2.1",
"winston-transport": "^4.7.0",
diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts
index ab80dcff04..f4fae0715b 100644
--- a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts
+++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts
@@ -19,6 +19,8 @@ import { ConfigReader } from '@backstage/config';
import { DatabaseTaskStore } from './DatabaseTaskStore';
import { TaskSpec } from '@backstage/plugin-scaffolder-common';
import { ConflictError } from '@backstage/errors';
+import { createMockDirectory } from '@backstage/backend-test-utils';
+import fs from 'fs-extra';
const createStore = async () => {
const manager = DatabaseManager.fromConfig(
@@ -37,6 +39,18 @@ const createStore = async () => {
return { store, manager };
};
+const workspaceDir = createMockDirectory({
+ content: {
+ 'app-config.yaml': `
+ app:
+ title: Example App
+ sessionKey:
+ $file: secrets/session-key.txt
+ escaped: \$\${Escaped}
+ `,
+ },
+});
+
describe('DatabaseTaskStore', () => {
it('should create the database store and run migration', async () => {
const { store, manager } = await createStore();
@@ -259,4 +273,22 @@ describe('DatabaseTaskStore', () => {
},
});
});
+
+ it('serialize and restore the workspace', async () => {
+ const { store } = await createStore();
+ const { taskId } = await store.createTask({
+ spec: {} as TaskSpec,
+ createdBy: 'me',
+ });
+
+ await store.serializeWorkspace({ path: workspaceDir.path, taskId });
+ expect(fs.existsSync(`${workspaceDir.path}/app-config.yaml`)).toBeTruthy();
+
+ fs.removeSync(workspaceDir.path);
+ expect(fs.existsSync(`${workspaceDir.path}/app-config.yaml`)).toBeFalsy();
+
+ fs.mkdirSync(workspaceDir.path);
+ await store.rehydrateWorkspace({ targetPath: workspaceDir.path, taskId });
+ expect(fs.existsSync(`${workspaceDir.path}/app-config.yaml`)).toBeTruthy();
+ });
});
diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts
index ac391ea2b6..f6f00b0441 100644
--- a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts
+++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts
@@ -42,6 +42,7 @@ import { DateTime, Duration } from 'luxon';
import { TaskRecovery, TaskSpec } from '@backstage/plugin-scaffolder-common';
import { trimEventsTillLastRecovery } from './taskRecoveryHelper';
import { intervalFromNowTill } from './dbUtil';
+import { restoreWorkspace, serializeWorkspace } from './serializer';
const migrationsDir = resolvePackagePath(
'@backstage/plugin-scaffolder-backend',
@@ -57,6 +58,7 @@ export type RawDbTaskRow = {
created_at: string;
created_by: string | null;
secrets?: string | null;
+ workspace?: Buffer;
};
export type RawDbTaskEventRow = {
@@ -509,6 +511,36 @@ export class DatabaseTaskStore implements TaskStore {
});
}
+ async rehydrateWorkspace(options: {
+ taskId: string;
+ targetPath: string;
+ }): Promise {
+ const [result] = await this.db('tasks')
+ .where({ id: options.taskId })
+ .select('workspace');
+
+ await restoreWorkspace(options.targetPath, result.workspace);
+ }
+
+ async cleanWorkspace({ taskId }: { taskId: string }): Promise {
+ await this.db('tasks').where({ id: taskId }).update({
+ workspace: undefined,
+ });
+ }
+
+ async serializeWorkspace(options: {
+ path: string;
+ taskId: string;
+ }): Promise {
+ if (options.path) {
+ await this.db('tasks')
+ .where({ id: options.taskId })
+ .update({
+ workspace: await serializeWorkspace(options.path),
+ });
+ }
+ }
+
async cancelTask(
options: TaskStoreEmitOptions<{ message: string } & JsonObject>,
): Promise {
diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts
index 5d24ac7cc7..77097e97ea 100644
--- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts
+++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts
@@ -419,6 +419,8 @@ export class NunjucksWorkflowRunner implements WorkflowRunner {
reason: stringifyError(err),
});
throw err;
+ } finally {
+ await task.serializeWorkspace?.({ path: workspacePath });
}
},
createTemporaryDirectory: async () => {
@@ -455,11 +457,14 @@ export class NunjucksWorkflowRunner implements WorkflowRunner {
throw new Error(`Step ${step.name} has been cancelled.`);
}
+ await task.cleanWorkspace?.();
await stepTrack.markSuccessful();
} catch (err) {
await taskTrack.markFailed(step, err);
await stepTrack.markFailed();
throw err;
+ } finally {
+ await task.serializeWorkspace?.({ path: workspacePath });
}
}
@@ -469,10 +474,9 @@ export class NunjucksWorkflowRunner implements WorkflowRunner {
'Wrong template version executed with the workflow engine',
);
}
- const workspacePath = path.join(
- this.options.workingDirectory,
- await task.getWorkspaceName(),
- );
+ const taskId = await task.getWorkspaceName();
+
+ const workspacePath = path.join(this.options.workingDirectory, taskId);
const { additionalTemplateFilters, additionalTemplateGlobals } =
this.options;
@@ -486,6 +490,8 @@ export class NunjucksWorkflowRunner implements WorkflowRunner {
});
try {
+ await task.rehydrateWorkspace?.({ taskId, targetPath: workspacePath });
+
const taskTrack = await this.tracker.taskStart(task);
await fs.ensureDir(workspacePath);
diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts
index e9a408d9d6..03a2833938 100644
--- a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts
+++ b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts
@@ -64,8 +64,16 @@ export class TaskManager implements TaskContext {
abortSignal: AbortSignal,
logger: Logger,
auth?: AuthService,
+ config?: Config,
) {
- const agent = new TaskManager(task, storage, abortSignal, logger, auth);
+ const agent = new TaskManager(
+ task,
+ storage,
+ abortSignal,
+ logger,
+ auth,
+ config,
+ );
agent.startTimeout();
return agent;
}
@@ -77,6 +85,7 @@ export class TaskManager implements TaskContext {
private readonly signal: AbortSignal,
private readonly logger: Logger,
private readonly auth?: AuthService,
+ private readonly config?: Config,
) {}
get spec() {
@@ -99,6 +108,15 @@ export class TaskManager implements TaskContext {
return this.task.taskId;
}
+ async rehydrateWorkspace?(options: {
+ taskId: string;
+ targetPath: string;
+ }): Promise {
+ if (this.isWorkspaceSerializationEnabled()) {
+ this.storage.rehydrateWorkspace?.(options);
+ }
+ }
+
get done() {
return this.isDone;
}
@@ -144,6 +162,21 @@ export class TaskManager implements TaskContext {
});
}
+ async serializeWorkspace?(options: { path: string }): Promise {
+ if (this.isWorkspaceSerializationEnabled()) {
+ await this.storage.serializeWorkspace?.({
+ path: options.path,
+ taskId: this.task.taskId,
+ });
+ }
+ }
+
+ async cleanWorkspace?(): Promise {
+ if (this.isWorkspaceSerializationEnabled()) {
+ await this.storage.cleanWorkspace?.({ taskId: this.task.taskId });
+ }
+ }
+
async complete(
result: TaskCompletionState,
metadata?: JsonObject,
@@ -178,6 +211,14 @@ export class TaskManager implements TaskContext {
}, 1000);
}
+ private isWorkspaceSerializationEnabled(): boolean {
+ return (
+ this.config?.getOptionalBoolean(
+ 'scaffolder.EXPERIMENTAL_workspaceSerialization',
+ ) ?? false
+ );
+ }
+
async getInitiatorCredentials(): Promise {
const secrets = this.task.secrets as InternalTaskSecrets;
@@ -219,6 +260,8 @@ export interface CurrentClaimedTask {
* The creator of the task.
*/
createdBy?: string;
+
+ workspace?: Promise;
}
function defer() {
@@ -322,6 +365,7 @@ export class StorageTaskBroker implements TaskBroker {
abortController.signal,
this.logger,
this.auth,
+ this.config,
);
}
diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/serializer.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/serializer.test.ts
new file mode 100644
index 0000000000..bec5398e28
--- /dev/null
+++ b/plugins/scaffolder-backend/src/scaffolder/tasks/serializer.test.ts
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { serializeWorkspace, restoreWorkspace } from './serializer';
+import { createMockDirectory } from '@backstage/backend-test-utils';
+import fs from 'fs-extra';
+
+describe('serializer', () => {
+ const workspaceDir = createMockDirectory({
+ content: {
+ 'app-config.yaml': `
+ app:
+ title: Example App
+ sessionKey:
+ $file: secrets/session-key.txt
+ escaped: \$\${Escaped}
+ `,
+ 'app-config2.yaml': `
+ app:
+ title: Example App 2
+ sessionKey:
+ $file: secrets/session-key.txt
+ escaped: \$\${Escaped}
+ `,
+ 'app-config.development.yaml': `
+ app:
+ sessionKey: development-key
+ backend:
+ $include: ./included.yaml
+ other:
+ $include: secrets/included.yaml
+ `,
+ 'secrets/session-key.txt': 'abc123',
+ 'secrets/included.yaml': `
+ secret:
+ $file: session-key.txt
+ `,
+ 'included.yaml': `
+ foo:
+ bar: token \${MY_SECRET}
+ `,
+ 'app-config.substitute.yaml': `
+ app:
+ someConfig:
+ $include: \${SUBSTITUTE_ME}.yaml
+ noSubstitute:
+ $file: \$\${ESCAPE_ME}.txt
+ `,
+ 'substituted.yaml': `
+ secret:
+ $file: secrets/\${SUBSTITUTE_ME}.txt
+ `,
+ 'secrets/substituted.txt': '123abc',
+ '${ESCAPE_ME}.txt': 'notSubstituted',
+ 'empty.yaml': '# just a comment',
+ },
+ });
+
+ const restoredWorkspaceDir = createMockDirectory();
+
+ it('should be able to archive and restore the workspace', async () => {
+ const workspaceBuffer = await serializeWorkspace(workspaceDir.path);
+ await restoreWorkspace(restoredWorkspaceDir.path, workspaceBuffer);
+
+ expect(
+ fs.existsSync(`${restoredWorkspaceDir.path}/\$\{ESCAPE_ME\}.txt`),
+ ).toBeTruthy();
+ expect(
+ fs.existsSync(`${restoredWorkspaceDir.path}/app-config.development.yaml`),
+ ).toBeTruthy();
+ expect(
+ fs.existsSync(`${restoredWorkspaceDir.path}/app-config.substitute.yaml`),
+ ).toBeTruthy();
+ expect(
+ fs.existsSync(`${restoredWorkspaceDir.path}/app-config.yaml`),
+ ).toBeTruthy();
+ expect(
+ fs.existsSync(`${restoredWorkspaceDir.path}/app-config2.yaml`),
+ ).toBeTruthy();
+ expect(
+ fs.existsSync(`${restoredWorkspaceDir.path}/empty.yaml`),
+ ).toBeTruthy();
+ expect(
+ fs.existsSync(`${restoredWorkspaceDir.path}/included.yaml`),
+ ).toBeTruthy();
+ expect(fs.existsSync(`${restoredWorkspaceDir.path}/secrets`)).toBeTruthy();
+ expect(
+ fs.existsSync(`${restoredWorkspaceDir.path}/substituted.yaml`),
+ ).toBeTruthy();
+
+ expect(
+ fs.readFileSync(`${restoredWorkspaceDir.path}/substituted.yaml`, 'utf8'),
+ ).toEqual(`
+ secret:
+ $file: secrets/\${SUBSTITUTE_ME}.txt
+ `);
+ });
+});
diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/serializer.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/serializer.ts
new file mode 100644
index 0000000000..69c48fb769
--- /dev/null
+++ b/plugins/scaffolder-backend/src/scaffolder/tasks/serializer.ts
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import tar from 'tar';
+import concatStream from 'concat-stream';
+import { promisify } from 'util';
+import { pipeline as pipelineCb, Readable } from 'stream';
+
+const pipeline = promisify(pipelineCb);
+
+export const serializeWorkspace = async (path: string): Promise => {
+ return await new Promise(async resolve => {
+ await pipeline(tar.create({ cwd: path }, ['']), concatStream(resolve));
+ });
+};
+
+export const restoreWorkspace = async (path: string, buffer?: Buffer) => {
+ if (buffer) {
+ await pipeline(
+ Readable.from(buffer),
+ tar.extract({
+ C: path,
+ }),
+ );
+ }
+};
diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts
index aa647d8bd6..0e0ebd706b 100644
--- a/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts
+++ b/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts
@@ -211,6 +211,21 @@ export interface TaskStore {
): Promise<{ events: SerializedTaskEvent[] }>;
shutdownTask?(options: TaskStoreShutDownTaskOptions): Promise;
+
+ rehydrateWorkspace?(options: {
+ taskId: string;
+ targetPath: string;
+ }): Promise;
+
+ cleanWorkspace?({ taskId }: { taskId: string }): Promise;
+
+ serializeWorkspace?({
+ path,
+ taskId,
+ }: {
+ path: string;
+ taskId: string;
+ }): Promise;
}
export type WorkflowResponse = { output: { [key: string]: JsonValue } };
diff --git a/plugins/scaffolder-node/api-report.md b/plugins/scaffolder-node/api-report.md
index c757301249..66e8ccd678 100644
--- a/plugins/scaffolder-node/api-report.md
+++ b/plugins/scaffolder-node/api-report.md
@@ -344,6 +344,8 @@ export interface TaskContext {
// (undocumented)
cancelSignal: AbortSignal;
// (undocumented)
+ cleanWorkspace?(): Promise;
+ // (undocumented)
complete(result: TaskCompletionState, metadata?: JsonObject): Promise;
// (undocumented)
createdBy?: string;
@@ -365,8 +367,15 @@ export interface TaskContext {
// (undocumented)
isDryRun?: boolean;
// (undocumented)
+ rehydrateWorkspace?(options: {
+ taskId: string;
+ targetPath: string;
+ }): Promise;
+ // (undocumented)
secrets?: TaskSecrets;
// (undocumented)
+ serializeWorkspace?(options: { path: string }): Promise;
+ // (undocumented)
spec: TaskSpec;
// (undocumented)
updateCheckpoint?(
diff --git a/plugins/scaffolder-node/src/tasks/types.ts b/plugins/scaffolder-node/src/tasks/types.ts
index aef2c5f360..a2adb97b9c 100644
--- a/plugins/scaffolder-node/src/tasks/types.ts
+++ b/plugins/scaffolder-node/src/tasks/types.ts
@@ -141,6 +141,15 @@ export interface TaskContext {
},
): Promise;
+ serializeWorkspace?(options: { path: string }): Promise;
+
+ cleanWorkspace?(): Promise;
+
+ rehydrateWorkspace?(options: {
+ taskId: string;
+ targetPath: string;
+ }): Promise;
+
getWorkspaceName(): Promise;
getInitiatorCredentials(): Promise;
diff --git a/yarn.lock b/yarn.lock
index 89d4b0ee45..cbdf845ac2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6803,6 +6803,7 @@ __metadata:
"@types/nunjucks": ^3.1.4
"@types/supertest": ^2.0.8
"@types/zen-observable": ^0.8.0
+ concat-stream: ^2.0.0
esbuild: ^0.20.0
express: ^4.17.1
express-promise-router: ^4.1.0
@@ -6821,6 +6822,7 @@ __metadata:
prom-client: ^15.0.0
strip-ansi: ^7.1.0
supertest: ^6.1.3
+ tar: ^6.1.12
uuid: ^9.0.0
wait-for-expect: ^3.0.2
winston: ^3.2.1