From f025822f29dbbde1dd690d89a6a68bfe4e3dd0a9 Mon Sep 17 00:00:00 2001 From: Quek Ruo Ling Date: Tue, 15 Sep 2026 15:19:34 +0800 Subject: [PATCH 1/4] [CCUBE-2284][RL] Split pull request checks from main --- .github/workflows/README.md | 30 ++++++--- .github/workflows/pr-checks.yml | 67 +++++++++++++++++++ .github/workflows/trigger-gitlab-pipeline.yml | 6 +- 3 files changed, 89 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/pr-checks.yml diff --git a/.github/workflows/README.md b/.github/workflows/README.md index dd3c8cb..188ea41 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -1,22 +1,20 @@ # GitHub Workflow for LifeSG libs -This guide will breifly explain what how the GitHub workflow works for LifeSG and the necessary setups to get it working on another LifeSG GitHub repository. +This guide will briefly explain what how the GitHub workflow works for LifeSG and the necessary setups to get it working on another LifeSG GitHub repository. -## trigger-gitlab-pipeline.yml +## trigger-gitlab-pipeline.yml -This file is responsible for creating the GitHub workflow and the job that triggers the GitLab pipeline. +This file is responsible for the job that triggers the GitLab pipeline. --- +## pr-checks.yml -## Trigger Pipeline Job +This file is responsible for running test and build checks on pull requests. -When a GitHub `push on master branch` or `pull request` is made it will trigger the job. +-- -Pull Request events that will trigger the pipeline are: +## Trigger Pipeline Job -- `opened`: when opening of a PR -- `synchronize`: when a new commit is added to the PR -- `reopened`: when reopening of a PR +When a GitHub `push on master branch` is made it will trigger the job. We have set variables in the settings of the GitHub repository that is needed to be passed into the trigger pipeline API. @@ -42,3 +40,15 @@ The API contains variables that are important to be passed in the body of the re Then the Project in GitLab responsible for running the pipeline will create and start the pipeline. The GitHub action is marked as successful when the GitLab pipeline's `build-dist-job` is successful. After that you are able to deploy to storybook/github/npm. + +## PR Checks + +When a GitHub `pull request` is made it will trigger the job. + +Pull Request events that will trigger the pipeline are: + +- `opened`: when opening of a PR +- `synchronize`: when a new commit is added to the PR +- `reopened`: when reopening of a PR + +The GitHub action is marked as successful when all check pass. diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml new file mode 100644 index 0000000..2d3032c --- /dev/null +++ b/.github/workflows/pr-checks.yml @@ -0,0 +1,67 @@ +name: PR Checks + +on: + pull_request: + types: [opened, synchronize, reopened] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + prepare-deps: + timeout-minutes: 5 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-node@v7 + with: + node-version: 22 + - name: Install dependencies + run: npm ci + - name: Pack dependencies + run: tar -czf node-modules.tgz node_modules + - name: Upload dependencies artifact + uses: actions/upload-artifact@v7 + with: + name: node-modules-tar + path: node-modules.tgz + retention-days: 1 + + build-lib: + needs: prepare-deps + timeout-minutes: 5 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-node@v7 + with: + node-version: 22 + - name: Download dependencies artifact + uses: actions/download-artifact@v8 + with: + name: node-modules-tar + path: . + - name: Restore dependencies + run: tar -xzf node-modules.tgz + - name: Build library + run: npm run build-lib + + build-storybook: + needs: prepare-deps + timeout-minutes: 5 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-node@v7 + with: + node-version: 22 + - name: Download dependencies artifact + uses: actions/download-artifact@v8 + with: + name: node-modules-tar + path: . + - name: Restore dependencies + run: tar -xzf node-modules.tgz + - name: Build Storybook + run: npm run build-storybook diff --git a/.github/workflows/trigger-gitlab-pipeline.yml b/.github/workflows/trigger-gitlab-pipeline.yml index 569f55a..b440287 100644 --- a/.github/workflows/trigger-gitlab-pipeline.yml +++ b/.github/workflows/trigger-gitlab-pipeline.yml @@ -6,8 +6,6 @@ on: - main - "release/**" - "!release/**-published" - pull_request: - types: [opened, synchronize, reopened] jobs: trigger_pipeline: @@ -16,9 +14,9 @@ jobs: steps: - name: Print Configs run: | - [[ $GITHUB_EVENT_NAME = "pull_request" ]] && BRANCH_NAME="${{ github.head_ref }}" || BRANCH_NAME="${{ github.ref_name }}" + BRANCH_NAME="${{ github.ref_name }}" - [[ $GITHUB_EVENT_NAME = "pull_request" ]] && COMMIT_MSG="${{ github.event.pull_request.title }}" || COMMIT_MSG=$(echo -e "${{ github.event.head_commit.message }}" | head -n 1) + COMMIT_MSG=$(echo -e "${{ github.event.head_commit.message }}" | head -n 1) PIPELINE_PROJECT_URL="github.com/$GITHUB_REPOSITORY.git" From 033d62a96effe31825b13d92bc41c9c4ab269dcb Mon Sep 17 00:00:00 2001 From: Quek Ruo Ling Date: Tue, 15 Sep 2026 15:26:30 +0800 Subject: [PATCH 2/4] [CCUBE-2284][RL] Prevent script injection via PR title/branch name in workflow --- .github/workflows/trigger-gitlab-pipeline.yml | 7 +++++-- package.json | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/trigger-gitlab-pipeline.yml b/.github/workflows/trigger-gitlab-pipeline.yml index b440287..691a11b 100644 --- a/.github/workflows/trigger-gitlab-pipeline.yml +++ b/.github/workflows/trigger-gitlab-pipeline.yml @@ -13,10 +13,13 @@ jobs: steps: - name: Print Configs + env: + REF_NAME: ${{ github.ref_name }} + HEAD_COMMIT_MSG: ${{ github.event.head_commit.message }} run: | - BRANCH_NAME="${{ github.ref_name }}" + BRANCH_NAME="$REF_NAME" - COMMIT_MSG=$(echo -e "${{ github.event.head_commit.message }}" | head -n 1) + COMMIT_MSG=$(printf '%s\n' "$HEAD_COMMIT_MSG" | awk 'NR>1{exit};1') PIPELINE_PROJECT_URL="github.com/$GITHUB_REPOSITORY.git" diff --git a/package.json b/package.json index 8180fd7..97b289b 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "typings": "dist/index.d.ts", "scripts": { "build": "npm run generate-icons && npm run rollup && npm run post:build", + "build-lib": "./scripts/build.sh", "build-check": "npm run rollup", "rollup": "rm -rf dist && rollup -c", "post:build": "node ./scripts/post-build.js", From fa56180e1078805831207016fadbb05a5037b7f3 Mon Sep 17 00:00:00 2001 From: Quek Ruo Ling Date: Tue, 15 Sep 2026 15:42:15 +0800 Subject: [PATCH 3/4] [CCUBE-2284][RL] Validate asset file name format --- scripts/generate-icons.js | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/scripts/generate-icons.js b/scripts/generate-icons.js index 3b67153..81a4ee1 100644 --- a/scripts/generate-icons.js +++ b/scripts/generate-icons.js @@ -51,7 +51,7 @@ async function transformToJSX(file) { // ============================================================================= // RUNNABLE // ============================================================================= -async function deleteFiles() { +async function deleteComponentFiles() { const files = await readdir(destinationPath); for (const file of files) { @@ -62,8 +62,29 @@ async function deleteFiles() { console.log(`Deleted ${files.length} files`); } +async function getSvgFiles() { + const files = await readdir(assetPath); + const componentFiles = files.filter((file) => file !== "index.ts"); + + // Validate file names are in the correct format + for (const file of componentFiles) { + const fileNameParts = file.split("."); + if ( + fileNameParts.length !== 2 || + !/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(fileNameParts[0]) || + fileNameParts[1] !== "svg" + ) { + throw new Error( + `Invalid file name: ${file}. SVG files should be in kebab case` + ); + } + } + + return componentFiles; +} + async function writeComponentFiles() { - const svgFiles = await readdir(assetPath); + const svgFiles = await getSvgFiles(); for (const file of svgFiles) { const jsxCode = await transformToJSX(file); @@ -100,7 +121,7 @@ async function generateIndexFile() { async function run() { try { - await deleteFiles(); + await deleteComponentFiles(); await writeComponentFiles(); await generateIndexFile(); } catch (err) { From 635e0f9a2338d9393866d61a581492d554677853 Mon Sep 17 00:00:00 2001 From: Quek Ruo Ling Date: Tue, 15 Sep 2026 16:38:35 +0800 Subject: [PATCH 4/4] [CCUBE-2284][RL] Edits after proofreading --- .github/workflows/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 188ea41..6c2f9ce 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -1,6 +1,6 @@ # GitHub Workflow for LifeSG libs -This guide will briefly explain what how the GitHub workflow works for LifeSG and the necessary setups to get it working on another LifeSG GitHub repository. +This guide will briefly explain how the GitHub workflow works for LifeSG and the necessary setups to get it working on another LifeSG GitHub repository. ## trigger-gitlab-pipeline.yml @@ -10,7 +10,7 @@ This file is responsible for the job that triggers the GitLab pipeline. This file is responsible for running test and build checks on pull requests. --- +--- ## Trigger Pipeline Job @@ -51,4 +51,4 @@ Pull Request events that will trigger the pipeline are: - `synchronize`: when a new commit is added to the PR - `reopened`: when reopening of a PR -The GitHub action is marked as successful when all check pass. +The GitHub action is marked as successful when all checks pass.