mirror of
https://github.com/penpot/penpot.git
synced 2026-10-04 17:56:14 +00:00
🐛 Fix script injection in GitHub Actions workflows
Values coming from `${{ }}` expressions were interpolated directly into
`run:` scripts, so GitHub substituted them into the shell source before
bash parsed it. A commit title containing a double quote broke the
"Write step summary" step of the bundle build with a syntax error, and
the same pattern allowed arbitrary command execution on the
self-hosted runners.
Pass every expression used inside `run:` through step/job `env:` and
reference it as a quoted shell variable instead. Use the runner's
default variables (GITHUB_RUN_ID, GITHUB_REPOSITORY, ...) where the
value comes from the `github` context.
Also validate `plugin_name` in plugins-deploy-package.yml against
`^[a-z0-9][a-z0-9-]*$`, since it is free-form and reaches paths,
worker names, GITHUB_ENV and action inputs.
Affected workflows: build-bundle, build-docker,
build-docker-admin-console, plugins-deploy-package,
plugins-deploy-api-doc, plugins-deploy-styles-doc, release, tests-e2e.
Signed-off-by: David Barragán Merino <david.barragan@kaleidos.net>
This commit is contained in:
parent
c0714def01
commit
534b1a6702
31
.github/workflows/build-bundle.yml
vendored
31
.github/workflows/build-bundle.yml
vendored
@ -62,8 +62,10 @@ jobs:
|
|||||||
|
|
||||||
- name: Extract some useful variables
|
- name: Extract some useful variables
|
||||||
id: vars
|
id: vars
|
||||||
|
env:
|
||||||
|
GH_REF: ${{ inputs.gh_ref || github.ref_name }}
|
||||||
run: |
|
run: |
|
||||||
echo "gh_ref=${{ inputs.gh_ref || github.ref_name }}" >> $GITHUB_OUTPUT
|
echo "gh_ref=$GH_REF" >> $GITHUB_OUTPUT
|
||||||
echo "bundle_version=$(git describe --tags --always)" >> $GITHUB_OUTPUT
|
echo "bundle_version=$(git describe --tags --always)" >> $GITHUB_OUTPUT
|
||||||
echo "short_sha=$(git rev-parse --short=12 HEAD)" >> $GITHUB_OUTPUT
|
echo "short_sha=$(git rev-parse --short=12 HEAD)" >> $GITHUB_OUTPUT
|
||||||
echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
||||||
@ -79,8 +81,12 @@ jobs:
|
|||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
|
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
|
||||||
|
S3_BUCKET: ${{ secrets.S3_BUCKET }}
|
||||||
|
FORCE: ${{ inputs.force }}
|
||||||
|
SHORT_SHA: ${{ steps.vars.outputs.short_sha }}
|
||||||
|
BUNDLE_VERSION: ${{ steps.vars.outputs.bundle_version }}
|
||||||
run: |
|
run: |
|
||||||
if [ "${{ inputs.force }}" = "true" ]; then
|
if [ "$FORCE" = "true" ]; then
|
||||||
echo "exists=false" >> $GITHUB_OUTPUT
|
echo "exists=false" >> $GITHUB_OUTPUT
|
||||||
{
|
{
|
||||||
echo "### 🔁 Bundle build forced"
|
echo "### 🔁 Bundle build forced"
|
||||||
@ -91,8 +97,8 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
BUNDLE_EXISTS=$(aws s3api head-object \
|
BUNDLE_EXISTS=$(aws s3api head-object \
|
||||||
--bucket ${{ secrets.S3_BUCKET }} \
|
--bucket "$S3_BUCKET" \
|
||||||
--key "penpot-sha-${{ steps.vars.outputs.short_sha }}.zip" \
|
--key "penpot-sha-${SHORT_SHA}.zip" \
|
||||||
> /dev/null 2>&1 && echo "true" || echo "false")
|
> /dev/null 2>&1 && echo "true" || echo "false")
|
||||||
|
|
||||||
if [ "$BUNDLE_EXISTS" = "true" ]; then
|
if [ "$BUNDLE_EXISTS" = "true" ]; then
|
||||||
@ -100,7 +106,7 @@ jobs:
|
|||||||
{
|
{
|
||||||
echo "### ⏭️ Bundle build skipped"
|
echo "### ⏭️ Bundle build skipped"
|
||||||
echo ""
|
echo ""
|
||||||
echo "The bundle in S3 was already built from \`sha-${{ steps.vars.outputs.short_sha }}\` (\`${{ steps.vars.outputs.bundle_version }}\`)."
|
echo "The bundle in S3 was already built from \`sha-${SHORT_SHA}\` (\`${BUNDLE_VERSION}\`)."
|
||||||
} >> "$GITHUB_STEP_SUMMARY"
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
else
|
else
|
||||||
echo "exists=false" >> $GITHUB_OUTPUT
|
echo "exists=false" >> $GITHUB_OUTPUT
|
||||||
@ -142,18 +148,25 @@ jobs:
|
|||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
|
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
|
||||||
|
S3_BUCKET: ${{ secrets.S3_BUCKET }}
|
||||||
|
SHORT_SHA: ${{ needs.check.outputs.short_sha }}
|
||||||
|
BUNDLE_VERSION: ${{ needs.check.outputs.bundle_version }}
|
||||||
run: |
|
run: |
|
||||||
aws s3 cp zips/penpot.zip \
|
aws s3 cp zips/penpot.zip \
|
||||||
s3://${{ secrets.S3_BUCKET }}/penpot-sha-${{ needs.check.outputs.short_sha }}.zip \
|
"s3://${S3_BUCKET}/penpot-sha-${SHORT_SHA}.zip" \
|
||||||
--metadata bundle-version=${{ needs.check.outputs.bundle_version }}
|
--metadata "bundle-version=${BUNDLE_VERSION}"
|
||||||
|
|
||||||
- name: Write step summary
|
- name: Write step summary
|
||||||
|
env:
|
||||||
|
SHORT_SHA: ${{ needs.check.outputs.short_sha }}
|
||||||
|
BUNDLE_VERSION: ${{ needs.check.outputs.bundle_version }}
|
||||||
|
COMMIT_TITLE: ${{ needs.check.outputs.commit_title }}
|
||||||
run: |
|
run: |
|
||||||
{
|
{
|
||||||
echo "### ✅ Bundle built"
|
echo "### ✅ Bundle built"
|
||||||
echo ""
|
echo ""
|
||||||
echo "- Version: \`${{ needs.check.outputs.bundle_version }}\` (\`git describe --tags --always\`)"
|
echo "- Version: \`${BUNDLE_VERSION}\` (\`git describe --tags --always\`)"
|
||||||
echo "- Commit: [\`${{ needs.check.outputs.short_sha }}\`](https://github.com/${{ github.repository }}/commit/${{ needs.check.outputs.short_sha }}) — ${{ needs.check.outputs.commit_title }}"
|
echo "- Commit: [\`${SHORT_SHA}\`](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/commit/${SHORT_SHA}) — ${COMMIT_TITLE}"
|
||||||
echo "- Built at: $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
|
echo "- Built at: $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
|
||||||
} >> "$GITHUB_STEP_SUMMARY"
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
|
||||||
|
|||||||
18
.github/workflows/build-docker-admin-console.yml
vendored
18
.github/workflows/build-docker-admin-console.yml
vendored
@ -48,16 +48,17 @@ jobs:
|
|||||||
WORKFLOW: build-docker-admin-console.yml
|
WORKFLOW: build-docker-admin-console.yml
|
||||||
GH_REF: ${{ inputs.gh_ref }}
|
GH_REF: ${{ inputs.gh_ref }}
|
||||||
DISPATCH_REF: ${{ inputs.dispatch_ref }}
|
DISPATCH_REF: ${{ inputs.dispatch_ref }}
|
||||||
|
FORCE: ${{ inputs.force }}
|
||||||
steps:
|
steps:
|
||||||
- name: Trigger nitrate docker build
|
- name: Trigger nitrate docker build
|
||||||
id: dispatch
|
id: dispatch
|
||||||
run: |
|
run: |
|
||||||
DISTINCT_ID="${{ github.run_id }}-${{ github.run_attempt }}"
|
DISTINCT_ID="${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
|
||||||
CALLER_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
CALLER_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
|
||||||
|
|
||||||
gh workflow run "$WORKFLOW" --repo "$REPO" --ref "$DISPATCH_REF" \
|
gh workflow run "$WORKFLOW" --repo "$REPO" --ref "$DISPATCH_REF" \
|
||||||
-f gh_ref="$GH_REF" \
|
-f gh_ref="$GH_REF" \
|
||||||
-f force="${{ inputs.force }}" \
|
-f force="$FORCE" \
|
||||||
-f caller_run_id="$DISTINCT_ID" \
|
-f caller_run_id="$DISTINCT_ID" \
|
||||||
-f caller_run_url="$CALLER_URL"
|
-f caller_run_url="$CALLER_URL"
|
||||||
|
|
||||||
@ -83,20 +84,25 @@ jobs:
|
|||||||
echo "::notice title=Nitrate docker build::$RUN_URL"
|
echo "::notice title=Nitrate docker build::$RUN_URL"
|
||||||
|
|
||||||
- name: Wait for nitrate docker build
|
- name: Wait for nitrate docker build
|
||||||
|
env:
|
||||||
|
RUN_ID: ${{ steps.dispatch.outputs.run_id }}
|
||||||
run: |
|
run: |
|
||||||
gh run watch "${{ steps.dispatch.outputs.run_id }}" \
|
gh run watch "$RUN_ID" \
|
||||||
--repo "$REPO" \
|
--repo "$REPO" \
|
||||||
--interval 30 \
|
--interval 30 \
|
||||||
--exit-status
|
--exit-status
|
||||||
|
|
||||||
- name: Report result
|
- name: Report result
|
||||||
if: always() && steps.dispatch.outputs.run_id != ''
|
if: always() && steps.dispatch.outputs.run_id != ''
|
||||||
|
env:
|
||||||
|
RUN_ID: ${{ steps.dispatch.outputs.run_id }}
|
||||||
|
RUN_URL: ${{ steps.dispatch.outputs.run_url }}
|
||||||
run: |
|
run: |
|
||||||
CONCLUSION=$(gh run view "${{ steps.dispatch.outputs.run_id }}" \
|
CONCLUSION=$(gh run view "$RUN_ID" \
|
||||||
--repo "$REPO" --json conclusion --jq '.conclusion')
|
--repo "$REPO" --json conclusion --jq '.conclusion')
|
||||||
{
|
{
|
||||||
echo "### 🐳 Nitrate docker build"
|
echo "### 🐳 Nitrate docker build"
|
||||||
echo ""
|
echo ""
|
||||||
echo "- Result: \`${CONCLUSION:-in_progress}\`"
|
echo "- Result: \`${CONCLUSION:-in_progress}\`"
|
||||||
echo "- Run: ${{ steps.dispatch.outputs.run_url }}"
|
echo "- Run: ${RUN_URL}"
|
||||||
} >> "$GITHUB_STEP_SUMMARY"
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
|||||||
77
.github/workflows/build-docker.yml
vendored
77
.github/workflows/build-docker.yml
vendored
@ -73,8 +73,9 @@ jobs:
|
|||||||
|
|
||||||
- name: Extract some useful variables
|
- name: Extract some useful variables
|
||||||
id: vars
|
id: vars
|
||||||
|
env:
|
||||||
|
GH_REF: ${{ inputs.gh_ref || github.ref_name }}
|
||||||
run: |
|
run: |
|
||||||
GH_REF="${{ inputs.gh_ref || github.ref_name }}"
|
|
||||||
echo "gh_ref=$GH_REF" >> $GITHUB_OUTPUT
|
echo "gh_ref=$GH_REF" >> $GITHUB_OUTPUT
|
||||||
echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
||||||
echo "short_sha=$(git rev-parse --short=12 HEAD)" >> $GITHUB_OUTPUT
|
echo "short_sha=$(git rev-parse --short=12 HEAD)" >> $GITHUB_OUTPUT
|
||||||
@ -92,13 +93,16 @@ jobs:
|
|||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
|
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
|
||||||
|
S3_BUCKET: ${{ secrets.S3_BUCKET }}
|
||||||
|
FORCE: ${{ inputs.force }}
|
||||||
|
SHORT_SHA: ${{ steps.vars.outputs.short_sha }}
|
||||||
run: |
|
run: |
|
||||||
if [ "${{ inputs.force }}" = "true" ]; then
|
if [ "$FORCE" = "true" ]; then
|
||||||
echo "exists=false" >> $GITHUB_OUTPUT
|
echo "exists=false" >> $GITHUB_OUTPUT
|
||||||
mkdir -p "$BUNDLE_CACHE"
|
mkdir -p "$BUNDLE_CACHE"
|
||||||
find "$BUNDLE_CACHE" -type f -mtime +1 -delete || true
|
find "$BUNDLE_CACHE" -type f -mtime +1 -delete || true
|
||||||
ZIP="$BUNDLE_CACHE/penpot-sha-${{ steps.vars.outputs.short_sha }}.zip"
|
ZIP="$BUNDLE_CACHE/penpot-sha-${SHORT_SHA}.zip"
|
||||||
aws s3 cp "s3://${{ secrets.S3_BUCKET }}/penpot-sha-${{ steps.vars.outputs.short_sha }}.zip" "$ZIP.$$.tmp"
|
aws s3 cp "s3://${S3_BUCKET}/penpot-sha-${SHORT_SHA}.zip" "$ZIP.$$.tmp"
|
||||||
mv "$ZIP.$$.tmp" "$ZIP"
|
mv "$ZIP.$$.tmp" "$ZIP"
|
||||||
{
|
{
|
||||||
echo "### 🔁 Image set build forced"
|
echo "### 🔁 Image set build forced"
|
||||||
@ -109,14 +113,14 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if aws s3api head-object \
|
if aws s3api head-object \
|
||||||
--bucket ${{ secrets.S3_BUCKET }} \
|
--bucket "$S3_BUCKET" \
|
||||||
--key "markers/images-sha-${{ steps.vars.outputs.short_sha }}" \
|
--key "markers/images-sha-${SHORT_SHA}" \
|
||||||
> /dev/null 2>&1; then
|
> /dev/null 2>&1; then
|
||||||
echo "exists=true" >> $GITHUB_OUTPUT
|
echo "exists=true" >> $GITHUB_OUTPUT
|
||||||
{
|
{
|
||||||
echo "### ⏭️ Image set build skipped"
|
echo "### ⏭️ Image set build skipped"
|
||||||
echo ""
|
echo ""
|
||||||
echo "The whole set was already built and promoted for \`sha-${{ steps.vars.outputs.short_sha }}\`."
|
echo "The whole set was already built and promoted for \`sha-${SHORT_SHA}\`."
|
||||||
} >> "$GITHUB_STEP_SUMMARY"
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
else
|
else
|
||||||
echo "exists=false" >> $GITHUB_OUTPUT
|
echo "exists=false" >> $GITHUB_OUTPUT
|
||||||
@ -126,9 +130,9 @@ jobs:
|
|||||||
# prune stale bundles while at it.
|
# prune stale bundles while at it.
|
||||||
mkdir -p "$BUNDLE_CACHE"
|
mkdir -p "$BUNDLE_CACHE"
|
||||||
find "$BUNDLE_CACHE" -type f -mtime +1 -delete || true
|
find "$BUNDLE_CACHE" -type f -mtime +1 -delete || true
|
||||||
ZIP="$BUNDLE_CACHE/penpot-sha-${{ steps.vars.outputs.short_sha }}.zip"
|
ZIP="$BUNDLE_CACHE/penpot-sha-${SHORT_SHA}.zip"
|
||||||
if [ ! -f "$ZIP" ]; then
|
if [ ! -f "$ZIP" ]; then
|
||||||
aws s3 cp "s3://${{ secrets.S3_BUCKET }}/penpot-sha-${{ steps.vars.outputs.short_sha }}.zip" "$ZIP.$$.tmp"
|
aws s3 cp "s3://${S3_BUCKET}/penpot-sha-${SHORT_SHA}.zip" "$ZIP.$$.tmp"
|
||||||
mv "$ZIP.$$.tmp" "$ZIP"
|
mv "$ZIP.$$.tmp" "$ZIP"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@ -197,18 +201,21 @@ jobs:
|
|||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
|
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
|
||||||
|
S3_BUCKET: ${{ secrets.S3_BUCKET }}
|
||||||
|
SHORT_SHA: ${{ needs.prepare.outputs.short_sha }}
|
||||||
|
IMAGE: ${{ matrix.image }}
|
||||||
run: |
|
run: |
|
||||||
ZIP="$BUNDLE_CACHE/penpot-sha-${{ needs.prepare.outputs.short_sha }}.zip"
|
ZIP="$BUNDLE_CACHE/penpot-sha-${SHORT_SHA}.zip"
|
||||||
if [ ! -f "$ZIP" ]; then
|
if [ ! -f "$ZIP" ]; then
|
||||||
echo "Bundle not found in host cache; falling back to S3."
|
echo "Bundle not found in host cache; falling back to S3."
|
||||||
mkdir -p "$BUNDLE_CACHE"
|
mkdir -p "$BUNDLE_CACHE"
|
||||||
aws s3 cp "s3://${{ secrets.S3_BUCKET }}/penpot-sha-${{ needs.prepare.outputs.short_sha }}.zip" "$ZIP.$$.tmp"
|
aws s3 cp "s3://${S3_BUCKET}/penpot-sha-${SHORT_SHA}.zip" "$ZIP.$$.tmp"
|
||||||
mv "$ZIP.$$.tmp" "$ZIP"
|
mv "$ZIP.$$.tmp" "$ZIP"
|
||||||
fi
|
fi
|
||||||
# Extract only the bundle this job needs.
|
# Extract only the bundle this job needs.
|
||||||
pushd docker/images
|
pushd docker/images
|
||||||
unzip -q "$ZIP" "penpot/${{ matrix.image }}/*"
|
unzip -q "$ZIP" "penpot/${IMAGE}/*"
|
||||||
mv "penpot/${{ matrix.image }}" "bundle-${{ matrix.image }}"
|
mv "penpot/${IMAGE}" "bundle-${IMAGE}"
|
||||||
popd
|
popd
|
||||||
|
|
||||||
- name: Set up QEMU (stable)
|
- name: Set up QEMU (stable)
|
||||||
@ -266,12 +273,16 @@ jobs:
|
|||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
- name: Point branch tags to the new build key
|
- name: Point branch tags to the new build key
|
||||||
|
env:
|
||||||
|
DOCKER_REGISTRY: ${{ secrets.DOCKER_REGISTRY }}
|
||||||
|
GH_REF: ${{ needs.prepare.outputs.gh_ref }}
|
||||||
|
SHORT_SHA: ${{ needs.prepare.outputs.short_sha }}
|
||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
for image in $ALL_IMAGES; do
|
for image in $ALL_IMAGES; do
|
||||||
docker buildx imagetools create \
|
docker buildx imagetools create \
|
||||||
-t "${{ secrets.DOCKER_REGISTRY }}/$image:${{ needs.prepare.outputs.gh_ref }}" \
|
-t "${DOCKER_REGISTRY}/${image}:${GH_REF}" \
|
||||||
"${{ secrets.DOCKER_REGISTRY }}/$image:sha-${{ needs.prepare.outputs.short_sha }}"
|
"${DOCKER_REGISTRY}/${image}:sha-${SHORT_SHA}"
|
||||||
done
|
done
|
||||||
|
|
||||||
# The marker is written LAST: its presence certifies that all five
|
# The marker is written LAST: its presence certifies that all five
|
||||||
@ -281,20 +292,27 @@ jobs:
|
|||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
|
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
|
||||||
|
S3_BUCKET: ${{ secrets.S3_BUCKET }}
|
||||||
|
SHORT_SHA: ${{ needs.prepare.outputs.short_sha }}
|
||||||
run: |
|
run: |
|
||||||
echo "${{ github.run_id }}" | aws s3 cp - \
|
echo "$GITHUB_RUN_ID" | aws s3 cp - \
|
||||||
"s3://${{ secrets.S3_BUCKET }}/markers/images-sha-${{ needs.prepare.outputs.short_sha }}"
|
"s3://${S3_BUCKET}/markers/images-sha-${SHORT_SHA}"
|
||||||
|
|
||||||
- name: Write step summary
|
- name: Write step summary
|
||||||
|
env:
|
||||||
|
GH_REF: ${{ needs.prepare.outputs.gh_ref }}
|
||||||
|
SHORT_SHA: ${{ needs.prepare.outputs.short_sha }}
|
||||||
|
BUNDLE_VERSION: ${{ needs.prepare.outputs.bundle_version }}
|
||||||
|
COMMIT_TITLE: ${{ needs.prepare.outputs.commit_title }}
|
||||||
run: |
|
run: |
|
||||||
{
|
{
|
||||||
echo "### ✅ Image set promoted"
|
echo "### ✅ Image set promoted"
|
||||||
echo ""
|
echo ""
|
||||||
echo "- Version: \`${{ needs.prepare.outputs.bundle_version }}\` (\`git describe --tags --always\`)"
|
echo "- Version: \`${BUNDLE_VERSION}\` (\`git describe --tags --always\`)"
|
||||||
echo "- Commit: [\`${{ needs.prepare.outputs.short_sha }}\`](https://github.com/${{ github.repository }}/commit/${{ needs.prepare.outputs.short_sha }}) — ${{ needs.prepare.outputs.commit_title }}"
|
echo "- Commit: [\`${SHORT_SHA}\`](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/commit/${SHORT_SHA}) — ${COMMIT_TITLE}"
|
||||||
echo "- Built at: $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
|
echo "- Built at: $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
|
||||||
echo ""
|
echo ""
|
||||||
echo "All \`:${{ needs.prepare.outputs.gh_ref }}\` tags now point to \`sha-${{ needs.prepare.outputs.short_sha }}\`."
|
echo "All \`:${GH_REF}\` tags now point to \`sha-${SHORT_SHA}\`."
|
||||||
} >> "$GITHUB_STEP_SUMMARY"
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
|
||||||
# ── 3b. Skip path: make sure THIS ref's tags point to the existing
|
# ── 3b. Skip path: make sure THIS ref's tags point to the existing
|
||||||
@ -324,24 +342,33 @@ jobs:
|
|||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
- name: Point branch tags to the existing build key
|
- name: Point branch tags to the existing build key
|
||||||
|
env:
|
||||||
|
DOCKER_REGISTRY: ${{ secrets.DOCKER_REGISTRY }}
|
||||||
|
GH_REF: ${{ needs.prepare.outputs.gh_ref }}
|
||||||
|
SHORT_SHA: ${{ needs.prepare.outputs.short_sha }}
|
||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
for image in $ALL_IMAGES; do
|
for image in $ALL_IMAGES; do
|
||||||
docker buildx imagetools create \
|
docker buildx imagetools create \
|
||||||
-t "${{ secrets.DOCKER_REGISTRY }}/$image:${{ needs.prepare.outputs.gh_ref }}" \
|
-t "${DOCKER_REGISTRY}/${image}:${GH_REF}" \
|
||||||
"${{ secrets.DOCKER_REGISTRY }}/$image:sha-${{ needs.prepare.outputs.short_sha }}"
|
"${DOCKER_REGISTRY}/${image}:sha-${SHORT_SHA}"
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: Write step summary
|
- name: Write step summary
|
||||||
|
env:
|
||||||
|
GH_REF: ${{ needs.prepare.outputs.gh_ref }}
|
||||||
|
SHORT_SHA: ${{ needs.prepare.outputs.short_sha }}
|
||||||
|
BUNDLE_VERSION: ${{ needs.prepare.outputs.bundle_version }}
|
||||||
|
COMMIT_TITLE: ${{ needs.prepare.outputs.commit_title }}
|
||||||
run: |
|
run: |
|
||||||
{
|
{
|
||||||
echo "### ✅ Image set already built (branch tags ensured)"
|
echo "### ✅ Image set already built (branch tags ensured)"
|
||||||
echo ""
|
echo ""
|
||||||
echo "- Version: \`${{ needs.prepare.outputs.bundle_version }}\` (\`git describe --tags --always\`)"
|
echo "- Version: \`${BUNDLE_VERSION}\` (\`git describe --tags --always\`)"
|
||||||
echo "- Commit: [\`${{ needs.prepare.outputs.short_sha }}\`](https://github.com/${{ github.repository }}/commit/${{ needs.prepare.outputs.short_sha }}) — ${{ needs.prepare.outputs.commit_title }}"
|
echo "- Commit: [\`${SHORT_SHA}\`](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/commit/${SHORT_SHA}) — ${COMMIT_TITLE}"
|
||||||
echo "- Checked at: $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
|
echo "- Checked at: $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
|
||||||
echo ""
|
echo ""
|
||||||
echo "All \`:${{ needs.prepare.outputs.gh_ref }}\` tags now point to \`sha-${{ needs.prepare.outputs.short_sha }}\`."
|
echo "All \`:${GH_REF}\` tags now point to \`sha-${SHORT_SHA}\`."
|
||||||
} >> "$GITHUB_STEP_SUMMARY"
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
|
||||||
# ── 4. Single failure notification for the whole workflow ─────────────
|
# ── 4. Single failure notification for the whole workflow ─────────────
|
||||||
|
|||||||
9
.github/workflows/plugins-deploy-api-doc.yml
vendored
9
.github/workflows/plugins-deploy-api-doc.yml
vendored
@ -33,8 +33,10 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Extract some useful variables
|
- name: Extract some useful variables
|
||||||
id: vars
|
id: vars
|
||||||
|
env:
|
||||||
|
GH_REF: ${{ inputs.gh_ref || github.ref_name }}
|
||||||
run: |
|
run: |
|
||||||
echo "gh_ref=${{ inputs.gh_ref || github.ref_name }}" >> $GITHUB_OUTPUT
|
echo "gh_ref=$GH_REF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
@ -78,8 +80,9 @@ jobs:
|
|||||||
run: pnpm run build:doc
|
run: pnpm run build:doc
|
||||||
|
|
||||||
- name: Select Worker name
|
- name: Select Worker name
|
||||||
|
env:
|
||||||
|
REF: ${{ steps.vars.outputs.gh_ref }}
|
||||||
run: |
|
run: |
|
||||||
REF="${{ steps.vars.outputs.gh_ref }}"
|
|
||||||
case "$REF" in
|
case "$REF" in
|
||||||
main)
|
main)
|
||||||
echo "WORKER_NAME=penpot-plugins-api-doc-pro" >> $GITHUB_ENV
|
echo "WORKER_NAME=penpot-plugins-api-doc-pro" >> $GITHUB_ENV
|
||||||
@ -97,7 +100,7 @@ jobs:
|
|||||||
working-directory: plugins
|
working-directory: plugins
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
sed -i "s/WORKER_URI/${{ env.WORKER_URI }}/g" wrangler-penpot-plugins-api-doc.toml
|
sed -i "s/WORKER_URI/${WORKER_URI}/g" wrangler-penpot-plugins-api-doc.toml
|
||||||
|
|
||||||
- name: Add noindex header and robots.txt files for non-production environments
|
- name: Add noindex header and robots.txt files for non-production environments
|
||||||
if: ${{ steps.vars.outputs.gh_ref != 'main' }}
|
if: ${{ steps.vars.outputs.gh_ref != 'main' }}
|
||||||
|
|||||||
34
.github/workflows/plugins-deploy-package.yml
vendored
34
.github/workflows/plugins-deploy-package.yml
vendored
@ -35,7 +35,20 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
runs-on: penpot-standar-runner
|
runs-on: penpot-standar-runner
|
||||||
|
env:
|
||||||
|
GH_REF: ${{ inputs.gh_ref }}
|
||||||
|
PLUGIN_NAME: ${{ inputs.plugin_name }}
|
||||||
steps:
|
steps:
|
||||||
|
# plugin_name is a free-form string that ends up in paths, worker names
|
||||||
|
# and GITHUB_ENV; reject anything that is not a plain slug before it is
|
||||||
|
# used anywhere.
|
||||||
|
- name: Validate inputs
|
||||||
|
run: |
|
||||||
|
if ! [[ "$PLUGIN_NAME" =~ ^[a-z0-9][a-z0-9-]*$ ]]; then
|
||||||
|
echo "::error::Invalid plugin_name: must match ^[a-z0-9][a-z0-9-]*$"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
@ -75,29 +88,28 @@ jobs:
|
|||||||
- name: "Build package for ${{ inputs.plugin_name }}-plugin"
|
- name: "Build package for ${{ inputs.plugin_name }}-plugin"
|
||||||
working-directory: plugins
|
working-directory: plugins
|
||||||
shell: bash
|
shell: bash
|
||||||
run: pnpm --filter ${{ inputs.plugin_name }}-plugin build
|
run: pnpm --filter "${PLUGIN_NAME}-plugin" build
|
||||||
|
|
||||||
- name: Select Worker name
|
- name: Select Worker name
|
||||||
run: |
|
run: |
|
||||||
REF="${{ inputs.gh_ref }}"
|
case "$GH_REF" in
|
||||||
case "$REF" in
|
|
||||||
main)
|
main)
|
||||||
echo "WORKER_NAME=${{ inputs.plugin_name }}-plugin-pro" >> $GITHUB_ENV
|
echo "WORKER_NAME=${PLUGIN_NAME}-plugin-pro" >> $GITHUB_ENV
|
||||||
echo "WORKER_URI=${{ inputs.plugin_name }}.plugins.penpot.app" >> $GITHUB_ENV ;;
|
echo "WORKER_URI=${PLUGIN_NAME}.plugins.penpot.app" >> $GITHUB_ENV ;;
|
||||||
staging)
|
staging)
|
||||||
echo "WORKER_NAME=${{ inputs.plugin_name }}-plugin-pre" >> $GITHUB_ENV
|
echo "WORKER_NAME=${PLUGIN_NAME}-plugin-pre" >> $GITHUB_ENV
|
||||||
echo "WORKER_URI=${{ inputs.plugin_name }}.plugins.penpot.dev" >> $GITHUB_ENV ;;
|
echo "WORKER_URI=${PLUGIN_NAME}.plugins.penpot.dev" >> $GITHUB_ENV ;;
|
||||||
develop)
|
develop)
|
||||||
echo "WORKER_NAME=${{ inputs.plugin_name }}-plugin-hourly" >> $GITHUB_ENV
|
echo "WORKER_NAME=${PLUGIN_NAME}-plugin-hourly" >> $GITHUB_ENV
|
||||||
echo "WORKER_URI=${{ inputs.plugin_name }}.plugins.hourly.penpot.dev" >> $GITHUB_ENV ;;
|
echo "WORKER_URI=${PLUGIN_NAME}.plugins.hourly.penpot.dev" >> $GITHUB_ENV ;;
|
||||||
*) echo "Unsupported branch ${REF}" && exit 1 ;;
|
*) echo "Unsupported branch ${GH_REF}" && exit 1 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
- name: Set the custom url
|
- name: Set the custom url
|
||||||
working-directory: plugins
|
working-directory: plugins
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
sed -i "s/WORKER_URI/${{ env.WORKER_URI }}/g" apps/${{ inputs.plugin_name }}-plugin/wrangler.toml
|
sed -i "s/WORKER_URI/${WORKER_URI}/g" "apps/${PLUGIN_NAME}-plugin/wrangler.toml"
|
||||||
|
|
||||||
- name: Deploy to Cloudflare Workers
|
- name: Deploy to Cloudflare Workers
|
||||||
uses: cloudflare/wrangler-action@v3
|
uses: cloudflare/wrangler-action@v3
|
||||||
|
|||||||
@ -31,8 +31,10 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Extract some useful variables
|
- name: Extract some useful variables
|
||||||
id: vars
|
id: vars
|
||||||
|
env:
|
||||||
|
GH_REF: ${{ inputs.gh_ref || github.ref_name }}
|
||||||
run: |
|
run: |
|
||||||
echo "gh_ref=${{ inputs.gh_ref || github.ref_name }}" >> $GITHUB_OUTPUT
|
echo "gh_ref=$GH_REF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
@ -76,8 +78,9 @@ jobs:
|
|||||||
run: pnpm run build:styles-example
|
run: pnpm run build:styles-example
|
||||||
|
|
||||||
- name: Select Worker name
|
- name: Select Worker name
|
||||||
|
env:
|
||||||
|
REF: ${{ steps.vars.outputs.gh_ref }}
|
||||||
run: |
|
run: |
|
||||||
REF="${{ steps.vars.outputs.gh_ref }}"
|
|
||||||
case "$REF" in
|
case "$REF" in
|
||||||
main)
|
main)
|
||||||
echo "WORKER_NAME=penpot-plugins-styles-doc-pro" >> $GITHUB_ENV
|
echo "WORKER_NAME=penpot-plugins-styles-doc-pro" >> $GITHUB_ENV
|
||||||
@ -95,7 +98,7 @@ jobs:
|
|||||||
working-directory: plugins
|
working-directory: plugins
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
sed -i "s/WORKER_URI/${{ env.WORKER_URI }}/g" wrangler-penpot-plugins-styles-doc.toml
|
sed -i "s/WORKER_URI/${WORKER_URI}/g" wrangler-penpot-plugins-styles-doc.toml
|
||||||
|
|
||||||
- name: Add noindex header and robots.txt files for non-production environments
|
- name: Add noindex header and robots.txt files for non-production environments
|
||||||
if: ${{ steps.vars.outputs.gh_ref != 'main' }}
|
if: ${{ steps.vars.outputs.gh_ref != 'main' }}
|
||||||
|
|||||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@ -26,8 +26,10 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Extract some useful variables
|
- name: Extract some useful variables
|
||||||
id: vars
|
id: vars
|
||||||
|
env:
|
||||||
|
GH_REF: ${{ inputs.gh_ref || github.ref_name }}
|
||||||
run: |
|
run: |
|
||||||
echo "gh_ref=${{ inputs.gh_ref || github.ref_name }}" >> $GITHUB_OUTPUT
|
echo "gh_ref=$GH_REF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|||||||
6
.github/workflows/tests-e2e.yml
vendored
6
.github/workflows/tests-e2e.yml
vendored
@ -190,12 +190,14 @@ jobs:
|
|||||||
working-directory: ./frontend
|
working-directory: ./frontend
|
||||||
env:
|
env:
|
||||||
WORKERS: ${{ inputs.workers }}
|
WORKERS: ${{ inputs.workers }}
|
||||||
|
SHARD: ${{ matrix.shard }}
|
||||||
|
SHARD_TOTAL: ${{ strategy.job-total }}
|
||||||
run: |
|
run: |
|
||||||
WORKERS=${WORKERS:-2}
|
WORKERS=${WORKERS:-2}
|
||||||
echo "Running shard ${{ matrix.shard }}/${{ strategy.job-total }} with $WORKERS workers"
|
echo "Running shard ${SHARD}/${SHARD_TOTAL} with $WORKERS workers"
|
||||||
pnpm exec playwright test --project default \
|
pnpm exec playwright test --project default \
|
||||||
--workers="$WORKERS" \
|
--workers="$WORKERS" \
|
||||||
--shard=${{ matrix.shard }}/${{ strategy.job-total }} \
|
--shard="${SHARD}/${SHARD_TOTAL}" \
|
||||||
--reporter=blob
|
--reporter=blob
|
||||||
|
|
||||||
- name: Upload blob report
|
- name: Upload blob report
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user