From 1c8bbf71f8ca2307a3b1235738f5fe68050989ed Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 16:55:58 +0100 Subject: [PATCH 01/20] Update docker.yaml --- .github/workflows/docker.yaml | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index c0e8301c..0f639535 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -62,16 +62,11 @@ on: type: string default: "" description: Use caching mechanism for a given language - submodules: - required: false - type: string - default: "" - description: True or Recursive to initialize git submodules repositories: required: false type: string default: "" - description: Comma or newline-separated list of repositories to grant access to during the docker build. + description: Comma or newline-separated list of additional repositories needed for Docker build (e.g., private dependencies) jobs: check: @@ -92,15 +87,15 @@ jobs: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_SECRET }} repositories: ${{ github.event.repository.name }}${{ inputs.repositories && format(',{0}', inputs.repositories) || '' }} + permission-contents: read - name: Checkout uses: actions/checkout@v6 with: - submodules: ${{ inputs.submodules }} - token: ${{ inputs.submodules != '' && steps.generate-token.outputs.token || github.token }} + token: ${{ needs.generate-token.outputs.token }} - name: Run pre-build env: - GH_TOKEN: ${{ steps.generate-token.outputs.token }} BUILD_SECRET: ${{ secrets.BUILD_SECRET }} + GH_TOKEN: ${{ needs.generate-token.outputs.token }} run: | if test -f "Makefile"; then make ci-pre-build @@ -175,8 +170,6 @@ jobs: labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max - secrets: | - "github_token=${{ steps.generate-token.outputs.token }}" build-args: | GIT_REV=${{fromJson(steps.meta.outputs.json).labels['org.opencontainers.image.revision']}} GIT_VERSION=${{fromJson(steps.meta.outputs.json).labels['org.opencontainers.image.version']}} @@ -192,7 +185,7 @@ jobs: run: | echo "tag=$(echo '${{ needs.build.outputs.tags }}' | head -n1)" >> "$GITHUB_OUTPUT" - name: Trivy vulnerability scanner - # trivy-action v0.35.0 (safe version) + # trivy-action v0.35.0 (safe version) - pinned to full commit SHA uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 with: scan-type: image From af794b876df5db0e5c6299c456fa8348797e0270 Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 17:28:56 +0100 Subject: [PATCH 02/20] refactor check-pr --- .github/workflows/check-pr.yaml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/check-pr.yaml b/.github/workflows/check-pr.yaml index 52031a08..e2795d2f 100644 --- a/.github/workflows/check-pr.yaml +++ b/.github/workflows/check-pr.yaml @@ -40,9 +40,15 @@ jobs: pr-label-check: if: ${{ github.event.pull_request.draft == false }} runs-on: ubuntu-latest + permissions: + pull-requests: read steps: - - uses: docker://agilepathway/pull-request-label-checker:latest + - uses: actions/github-script@v7 with: - github_enterprise_graphql_url: https://api.github.com/graphql - one_of: ${{ inputs.labels !='' && inputs.labels || 'feature,bug,ci,refactor,security,documentation,dependencies,customer,skip-changelog' }} - repo_token: ${{ secrets.GITHUB_TOKEN }} + script: | + const labels = context.payload.pull_request.labels.map(l => l.name); + const required = '${{ inputs.labels }}'.split(','); + const hasLabel = required.some(r => labels.includes(r.trim())); + if (!hasLabel) { + core.setFailed(`PR must have one of: ${required.join(', ')}`); + } From 6a5de10b1aa7d1854be6b8ab8be85d9d4e941c38 Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 17:31:31 +0100 Subject: [PATCH 03/20] comment if for testing --- .github/workflows/check-pr.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-pr.yaml b/.github/workflows/check-pr.yaml index e2795d2f..34c0565b 100644 --- a/.github/workflows/check-pr.yaml +++ b/.github/workflows/check-pr.yaml @@ -38,7 +38,7 @@ on: type: string jobs: pr-label-check: - if: ${{ github.event.pull_request.draft == false }} +# if: ${{ github.event.pull_request.draft == false }} runs-on: ubuntu-latest permissions: pull-requests: read From 24d571ebb8db2debd19b3ea339169cf66b9b3acc Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 17:44:00 +0100 Subject: [PATCH 04/20] Update check-pr.yaml --- .github/workflows/check-pr.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check-pr.yaml b/.github/workflows/check-pr.yaml index 34c0565b..0211fb5d 100644 --- a/.github/workflows/check-pr.yaml +++ b/.github/workflows/check-pr.yaml @@ -47,8 +47,11 @@ jobs: with: script: | const labels = context.payload.pull_request.labels.map(l => l.name); - const required = '${{ inputs.labels }}'.split(','); - const hasLabel = required.some(r => labels.includes(r.trim())); + const required = '${{ inputs.labels != '' && inputs.labels || 'feature,bug,ci,refactor,security,documentation,dependencies,customer,skip-changelog' }}' + .split(',') + .map(s => s.trim()) + .filter(Boolean); + const hasLabel = required.some(label => labels.includes(label)); if (!hasLabel) { core.setFailed(`PR must have one of: ${required.join(', ')}`); } From 8fa3f2745d3a54a8c9aa4bc98ff0f69559143859 Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 17:46:56 +0100 Subject: [PATCH 05/20] tested check-pr --- .github/workflows/check-pr.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-pr.yaml b/.github/workflows/check-pr.yaml index 0211fb5d..0b7722f8 100644 --- a/.github/workflows/check-pr.yaml +++ b/.github/workflows/check-pr.yaml @@ -38,7 +38,7 @@ on: type: string jobs: pr-label-check: -# if: ${{ github.event.pull_request.draft == false }} + if: ${{ github.event.pull_request.draft == false }} runs-on: ubuntu-latest permissions: pull-requests: read From 2f445f8774f0b3dda4884e5cd320df4b7d3a3334 Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 17:48:23 +0100 Subject: [PATCH 06/20] fix token passing --- .github/workflows/docker.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index 0f639535..45070fb8 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -91,11 +91,11 @@ jobs: - name: Checkout uses: actions/checkout@v6 with: - token: ${{ needs.generate-token.outputs.token }} + token: ${{ steps.generate-token.outputs.token }} - name: Run pre-build env: BUILD_SECRET: ${{ secrets.BUILD_SECRET }} - GH_TOKEN: ${{ needs.generate-token.outputs.token }} + GH_TOKEN: ${{ steps.generate-token.outputs.token }} run: | if test -f "Makefile"; then make ci-pre-build From 8a939941d50f07ee28f5eef399873addd7db01c4 Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 18:08:30 +0100 Subject: [PATCH 07/20] test add-to-project --- .github/workflows/add-to-project.yaml | 164 ++++++++++++++++++++++---- 1 file changed, 139 insertions(+), 25 deletions(-) diff --git a/.github/workflows/add-to-project.yaml b/.github/workflows/add-to-project.yaml index 7d05ff54..8e467e0d 100644 --- a/.github/workflows/add-to-project.yaml +++ b/.github/workflows/add-to-project.yaml @@ -43,13 +43,19 @@ jobs: if: github.event_name == 'issues' || github.event_name == 'pull_request' || github.event_name == 'workflow_call' name: Add issue/PR to a project runs-on: ubuntu-latest - permissions: write-all + permissions: + contents: read + pull-requests: read + issues: read steps: - uses: actions/create-github-app-token@v3 id: generate-token with: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_SECRET }} + permission-issues: write + permission-pull-requests: read + permission-contents: read - uses: actions/add-to-project@v1.0.2 id: add-project with: @@ -58,27 +64,111 @@ jobs: project-url: ${{ inputs.project-url != '' && inputs.project-url || secrets.PLATFORM_PROJECT_URL }} github-token: ${{ steps.generate-token.outputs.token }} labeled: ${{ inputs.labeled }} - - if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == true && steps.add-project.outputs.itemId }} - uses: titoportas/update-project-fields@v0.1.0 + - if: ${{ github.event_name == 'pull_request' && steps.add-project.outputs.itemId }} + uses: actions/github-script@v7 with: - project-url: ${{ inputs.project-url != '' && inputs.project-url || secrets.PLATFORM_PROJECT_URL }} - github-token: ${{ steps.generate-token.outputs.token }} - item-id: ${{ steps.add-project.outputs.itemId }} # Use the item-id output of the previous step - field-keys: Status - field-values: 🏗 In progress - - if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == false && steps.add-project.outputs.itemId }} - uses: titoportas/update-project-fields@v0.1.0 - with: - project-url: ${{ inputs.project-url != '' && inputs.project-url || secrets.PLATFORM_PROJECT_URL }} github-token: ${{ steps.generate-token.outputs.token }} - item-id: ${{ steps.add-project.outputs.itemId }} # Use the item-id output of the previous step - field-keys: Status - field-values: 🔖 Ready + script: | + const projectUrl = '${{ inputs.project-url != '' && inputs.project-url || secrets.PLATFORM_PROJECT_URL }}'; + const itemId = '${{ steps.add-project.outputs.itemId }}'; + const isDraft = ${{ github.event.pull_request.draft }}; + const statusValue = isDraft ? '🏗 In progress' : '🔖 Ready'; + + // Parse project URL to extract owner, repo (if needed), and project number + const match = projectUrl.match(/\/projects\/(\d+)/); + if (!match) { + core.setFailed('Could not parse project URL'); + return; + } + const projectNumber = match[1]; + + // Get the project to find the Status field ID + const projectQuery = ` + query { + node(id: "${itemId}") { + ... on ProjectV2Item { + id + project { + id + } + } + } + } + `; + + // Get project fields + const fieldsQuery = ` + query($number: Int!, $first: Int) { + organization(login: "${github.repository_owner}") { + projectV2(number: $number) { + id + fields(first: $first) { + nodes { + ... on ProjectV2Field { + id + name + } + ... on ProjectV2SingleSelectField { + id + name + } + } + } + } + } + } + `; + + try { + const fieldsResult = await github.graphql(fieldsQuery, { + number: parseInt(projectNumber), + first: 20 + }); + + const statusField = fieldsResult.organization?.projectV2?.fields?.nodes?.find( + f => f.name === 'Status' + ); + + if (!statusField) { + core.setFailed('Status field not found in project'); + return; + } + + // Update the field value + const updateMutation = ` + mutation { + updateProjectV2ItemFieldValue(input: { + projectId: "${fieldsResult.organization.projectV2.id}" + itemId: "${itemId}" + fieldId: "${statusField.id}" + value: { + text: "${statusValue}" + } + }) { + projectV2Item { + id + } + } + } + `; + + await github.graphql(updateMutation); + console.log(`Updated Status to: ${statusValue}`); + } catch (error) { + core.setFailed(`Failed to update project field: ${error.message}`); + } - name: Assign PR to creator - if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == false && steps.add-project.outputs.itemId }} - uses: thomaseizinger/assign-pr-creator-action@v1.0.0 + if: ${{ github.event_name == 'pull_request' && !github.event.pull_request.draft && steps.add-project.outputs.itemId }} + uses: actions/github-script@v7 with: - repo-token: ${{ secrets.GITHUB_TOKEN }} + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.rest.issues.addAssignees({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + assignees: [context.payload.pull_request.user.login] + }); - name: Add permissions if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == false && steps.add-project.outputs.itemId }} run: | @@ -98,11 +188,35 @@ jobs: REPO: ${{ github.event.repository.name }} TEAMS: ${{ inputs.reviewers-team != '' && inputs.reviewers-team || 'backend-devs,ops' }} - name: Add reviewers - if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == false && steps.add-project.outputs.itemId }} - uses: rowi1de/auto-assign-review-teams@v1.1.3 + if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == false && steps.add-project.outputs.itemId }} + uses: actions/github-script@v7 with: - repo-token: ${{ steps.generate-token.outputs.token }} - teams: ${{ inputs.reviewers-team != '' && inputs.reviewers-team || 'backend-devs,ops' }} # only works for GitHub Organisation/Teams - persons: ${{ inputs.reviewers-individuals }} # add individual persons here - include-draft: false # Draft PRs will be skipped (default: false) - skip-with-manual-reviewers: 1 # Skip this action, if the number of reviwers was already assigned (default: 0) + github-token: ${{ steps.generate-token.outputs.token }} + script: | + const teams = '${{ inputs.reviewers-team != '' && inputs.reviewers-team || 'backend-devs,ops' }}' + .split(',') + .map(t => t.trim()) + .filter(t => t); + + const persons = '${{ inputs.reviewers-individuals }}' + .split(',') + .map(p => p.trim()) + .filter(p => p); + + if (teams.length === 0 && persons.length === 0) { + console.log('No reviewers configured'); + return; + } + + try { + await github.rest.pulls.requestReviewers({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + reviewers: persons, + team_reviewers: teams + }); + console.log(`Requested reviewers: teams=[${teams}], persons=[${persons}]`); + } catch (error) { + core.warning(`Failed to request reviewers: ${error.message}`); + } From a83a4b77faad22e9675af0395a835ff3e2eb02d8 Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 18:12:08 +0100 Subject: [PATCH 08/20] Update add-to-project.yaml --- .github/workflows/add-to-project.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/add-to-project.yaml b/.github/workflows/add-to-project.yaml index 8e467e0d..eb3b05b2 100644 --- a/.github/workflows/add-to-project.yaml +++ b/.github/workflows/add-to-project.yaml @@ -53,9 +53,12 @@ jobs: with: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_SECRET }} + owner: ${{ github.repository_owner }} + repositories: ${{ github.event.repository.name }} permission-issues: write permission-pull-requests: read permission-contents: read + permission-organization-projects: write - uses: actions/add-to-project@v1.0.2 id: add-project with: From daedafb0a6498a7516616605c1d845df2a2861e4 Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 18:16:11 +0100 Subject: [PATCH 09/20] Update add-to-project.yaml --- .github/workflows/add-to-project.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/add-to-project.yaml b/.github/workflows/add-to-project.yaml index eb3b05b2..9e78625d 100644 --- a/.github/workflows/add-to-project.yaml +++ b/.github/workflows/add-to-project.yaml @@ -53,8 +53,6 @@ jobs: with: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_SECRET }} - owner: ${{ github.repository_owner }} - repositories: ${{ github.event.repository.name }} permission-issues: write permission-pull-requests: read permission-contents: read @@ -84,6 +82,7 @@ jobs: return; } const projectNumber = match[1]; + const orgLogin = context.repo.owner; // Get the project to find the Status field ID const projectQuery = ` @@ -102,7 +101,7 @@ jobs: // Get project fields const fieldsQuery = ` query($number: Int!, $first: Int) { - organization(login: "${github.repository_owner}") { + organization(login: "${orgLogin}") { projectV2(number: $number) { id fields(first: $first) { From 7778574165256fa34556fd0e6d32bfefdaabe1b2 Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 18:18:45 +0100 Subject: [PATCH 10/20] Update add-to-project.yaml --- .github/workflows/add-to-project.yaml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/add-to-project.yaml b/.github/workflows/add-to-project.yaml index 9e78625d..c6bebd4e 100644 --- a/.github/workflows/add-to-project.yaml +++ b/.github/workflows/add-to-project.yaml @@ -113,6 +113,10 @@ jobs: ... on ProjectV2SingleSelectField { id name + options { + id + name + } } } } @@ -135,6 +139,26 @@ jobs: core.setFailed('Status field not found in project'); return; } + + const normalize = (value) => + String(value || '') + .replace(/^\s*[^A-Za-z0-9]+\s*/, '') + .trim() + .toLowerCase(); + + const statusOptions = statusField.options || []; + const statusOption = + statusOptions.find((opt) => opt.name === statusValue) || + statusOptions.find((opt) => normalize(opt.name) === normalize(statusValue)); + + if (!statusOption) { + core.setFailed( + `Status option not found for "${statusValue}". Available options: ${statusOptions + .map((opt) => opt.name) + .join(', ')}` + ); + return; + } // Update the field value const updateMutation = ` @@ -144,7 +168,7 @@ jobs: itemId: "${itemId}" fieldId: "${statusField.id}" value: { - text: "${statusValue}" + singleSelectOptionId: "${statusOption.id}" } }) { projectV2Item { From 0c7516da0fc3f46354bfbe137e400834ba094449 Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 18:20:45 +0100 Subject: [PATCH 11/20] Update add-to-project.yaml --- .github/workflows/add-to-project.yaml | 76 ++++++++++++++++++--------- 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/.github/workflows/add-to-project.yaml b/.github/workflows/add-to-project.yaml index c6bebd4e..18f03a72 100644 --- a/.github/workflows/add-to-project.yaml +++ b/.github/workflows/add-to-project.yaml @@ -75,33 +75,47 @@ jobs: const isDraft = ${{ github.event.pull_request.draft }}; const statusValue = isDraft ? '🏗 In progress' : '🔖 Ready'; - // Parse project URL to extract owner, repo (if needed), and project number - const match = projectUrl.match(/\/projects\/(\d+)/); - if (!match) { - core.setFailed('Could not parse project URL'); + // Parse project URL, supports both: + // - https://github.com/orgs//projects/ + // - https://github.com/users//projects/ + const projectMatch = projectUrl.match(/github\.com\/(?:(orgs|users)\/)?([^/]+)\/projects\/(\d+)/i); + if (!projectMatch) { + core.setFailed(`Could not parse project URL: ${projectUrl}`); return; } - const projectNumber = match[1]; - const orgLogin = context.repo.owner; + const projectOwnerType = (projectMatch[1] || '').toLowerCase(); + const projectOwnerLogin = projectMatch[2]; + const projectNumber = Number(projectMatch[3]); + const isUserProject = projectOwnerType === 'users'; - // Get the project to find the Status field ID - const projectQuery = ` - query { - node(id: "${itemId}") { - ... on ProjectV2Item { + // Get project fields + const fieldsQuery = isUserProject ? ` + query($number: Int!, $first: Int) { + user(login: "${projectOwnerLogin}") { + projectV2(number: $number) { id - project { - id + fields(first: $first) { + nodes { + ... on ProjectV2Field { + id + name + } + ... on ProjectV2SingleSelectField { + id + name + options { + id + name + } + } + } } } } } - `; - - // Get project fields - const fieldsQuery = ` + ` : ` query($number: Int!, $first: Int) { - organization(login: "${orgLogin}") { + organization(login: "${projectOwnerLogin}") { projectV2(number: $number) { id fields(first: $first) { @@ -127,11 +141,15 @@ jobs: try { const fieldsResult = await github.graphql(fieldsQuery, { - number: parseInt(projectNumber), + number: projectNumber, first: 20 }); + + const projectNode = isUserProject + ? fieldsResult.user?.projectV2 + : fieldsResult.organization?.projectV2; - const statusField = fieldsResult.organization?.projectV2?.fields?.nodes?.find( + const statusField = projectNode?.fields?.nodes?.find( f => f.name === 'Status' ); @@ -147,11 +165,12 @@ jobs: .toLowerCase(); const statusOptions = statusField.options || []; + const isSingleSelect = Array.isArray(statusField.options); const statusOption = statusOptions.find((opt) => opt.name === statusValue) || statusOptions.find((opt) => normalize(opt.name) === normalize(statusValue)); - if (!statusOption) { + if (isSingleSelect && !statusOption) { core.setFailed( `Status option not found for "${statusValue}". Available options: ${statusOptions .map((opt) => opt.name) @@ -160,15 +179,24 @@ jobs: return; } - // Update the field value + const projectId = projectNode?.id; + if (!projectId) { + core.setFailed('Could not resolve project id from project URL and owner'); + return; + } + + // Update field value using the correct value type + const valueFragment = statusOption + ? `singleSelectOptionId: "${statusOption.id}"` + : `text: "${statusValue.replace(/"/g, '\\"')}"`; const updateMutation = ` mutation { updateProjectV2ItemFieldValue(input: { - projectId: "${fieldsResult.organization.projectV2.id}" + projectId: "${projectId}" itemId: "${itemId}" fieldId: "${statusField.id}" value: { - singleSelectOptionId: "${statusOption.id}" + ${valueFragment} } }) { projectV2Item { From 10717b6515cc509f78ba33bf1770e108baaf338e Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 18:22:52 +0100 Subject: [PATCH 12/20] test last steps --- .github/workflows/add-to-project.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/add-to-project.yaml b/.github/workflows/add-to-project.yaml index 18f03a72..1a98e33a 100644 --- a/.github/workflows/add-to-project.yaml +++ b/.github/workflows/add-to-project.yaml @@ -212,7 +212,7 @@ jobs: core.setFailed(`Failed to update project field: ${error.message}`); } - name: Assign PR to creator - if: ${{ github.event_name == 'pull_request' && !github.event.pull_request.draft && steps.add-project.outputs.itemId }} + #if: ${{ github.event_name == 'pull_request' && !github.event.pull_request.draft && steps.add-project.outputs.itemId }} uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} @@ -224,7 +224,7 @@ jobs: assignees: [context.payload.pull_request.user.login] }); - name: Add permissions - if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == false && steps.add-project.outputs.itemId }} + #if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == false && steps.add-project.outputs.itemId }} run: | IFS=, for TEAM in $TEAMS; @@ -242,7 +242,7 @@ jobs: REPO: ${{ github.event.repository.name }} TEAMS: ${{ inputs.reviewers-team != '' && inputs.reviewers-team || 'backend-devs,ops' }} - name: Add reviewers - if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == false && steps.add-project.outputs.itemId }} + #if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == false && steps.add-project.outputs.itemId }} uses: actions/github-script@v7 with: github-token: ${{ steps.generate-token.outputs.token }} From 39198169d326bb7bc3e46aad507a3e266acd125e Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 18:25:41 +0100 Subject: [PATCH 13/20] Update add-to-project.yaml --- .github/workflows/add-to-project.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/add-to-project.yaml b/.github/workflows/add-to-project.yaml index 1a98e33a..1f344ffe 100644 --- a/.github/workflows/add-to-project.yaml +++ b/.github/workflows/add-to-project.yaml @@ -54,7 +54,7 @@ jobs: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_SECRET }} permission-issues: write - permission-pull-requests: read + permission-pull-requests: write permission-contents: read permission-organization-projects: write - uses: actions/add-to-project@v1.0.2 @@ -215,9 +215,9 @@ jobs: #if: ${{ github.event_name == 'pull_request' && !github.event.pull_request.draft && steps.add-project.outputs.itemId }} uses: actions/github-script@v7 with: - github-token: ${{ secrets.GITHUB_TOKEN }} + github-token: ${{ steps.generate-token.outputs.token }} script: | - github.rest.issues.addAssignees({ + await github.rest.issues.addAssignees({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, From 868f3a16fd23cf3394b7614a77e602a8995f2a2d Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 18:31:10 +0100 Subject: [PATCH 14/20] fix permission --- .github/workflows/add-to-project.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/add-to-project.yaml b/.github/workflows/add-to-project.yaml index 1f344ffe..ef1c8fdf 100644 --- a/.github/workflows/add-to-project.yaml +++ b/.github/workflows/add-to-project.yaml @@ -56,6 +56,7 @@ jobs: permission-issues: write permission-pull-requests: write permission-contents: read + permission-members: read permission-organization-projects: write - uses: actions/add-to-project@v1.0.2 id: add-project From ef4a094df94edc899b1ef1c3c29f566c9498ebb5 Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 18:35:34 +0100 Subject: [PATCH 15/20] Update add-to-project.yaml --- .github/workflows/add-to-project.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/add-to-project.yaml b/.github/workflows/add-to-project.yaml index ef1c8fdf..485f15f2 100644 --- a/.github/workflows/add-to-project.yaml +++ b/.github/workflows/add-to-project.yaml @@ -58,6 +58,7 @@ jobs: permission-contents: read permission-members: read permission-organization-projects: write + permission-administration: write - uses: actions/add-to-project@v1.0.2 id: add-project with: From 7b148e9c9f85f6752759229d120ebf9f32a48f0e Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 18:38:09 +0100 Subject: [PATCH 16/20] finalised hardened add-to-project --- .github/workflows/add-to-project.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/add-to-project.yaml b/.github/workflows/add-to-project.yaml index 485f15f2..315db34a 100644 --- a/.github/workflows/add-to-project.yaml +++ b/.github/workflows/add-to-project.yaml @@ -214,7 +214,7 @@ jobs: core.setFailed(`Failed to update project field: ${error.message}`); } - name: Assign PR to creator - #if: ${{ github.event_name == 'pull_request' && !github.event.pull_request.draft && steps.add-project.outputs.itemId }} + if: ${{ github.event_name == 'pull_request' && !github.event.pull_request.draft && steps.add-project.outputs.itemId }} uses: actions/github-script@v7 with: github-token: ${{ steps.generate-token.outputs.token }} @@ -226,7 +226,7 @@ jobs: assignees: [context.payload.pull_request.user.login] }); - name: Add permissions - #if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == false && steps.add-project.outputs.itemId }} + if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == false && steps.add-project.outputs.itemId }} run: | IFS=, for TEAM in $TEAMS; @@ -244,7 +244,7 @@ jobs: REPO: ${{ github.event.repository.name }} TEAMS: ${{ inputs.reviewers-team != '' && inputs.reviewers-team || 'backend-devs,ops' }} - name: Add reviewers - #if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == false && steps.add-project.outputs.itemId }} + if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == false && steps.add-project.outputs.itemId }} uses: actions/github-script@v7 with: github-token: ${{ steps.generate-token.outputs.token }} From bebbb048953b4d89db48337fa70664ae58d95c75 Mon Sep 17 00:00:00 2001 From: Bot Date: Thu, 26 Mar 2026 17:44:25 +0000 Subject: [PATCH 17/20] Automated yaml-lint fixes [dependabot skip] --- .github/workflows/add-to-project.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/add-to-project.yaml b/.github/workflows/add-to-project.yaml index 315db34a..fcc62700 100644 --- a/.github/workflows/add-to-project.yaml +++ b/.github/workflows/add-to-project.yaml @@ -76,7 +76,7 @@ jobs: const itemId = '${{ steps.add-project.outputs.itemId }}'; const isDraft = ${{ github.event.pull_request.draft }}; const statusValue = isDraft ? '🏗 In progress' : '🔖 Ready'; - + // Parse project URL, supports both: // - https://github.com/orgs//projects/ // - https://github.com/users//projects/ @@ -89,7 +89,7 @@ jobs: const projectOwnerLogin = projectMatch[2]; const projectNumber = Number(projectMatch[3]); const isUserProject = projectOwnerType === 'users'; - + // Get project fields const fieldsQuery = isUserProject ? ` query($number: Int!, $first: Int) { @@ -140,7 +140,7 @@ jobs: } } `; - + try { const fieldsResult = await github.graphql(fieldsQuery, { number: projectNumber, @@ -253,17 +253,17 @@ jobs: .split(',') .map(t => t.trim()) .filter(t => t); - + const persons = '${{ inputs.reviewers-individuals }}' .split(',') .map(p => p.trim()) .filter(p => p); - + if (teams.length === 0 && persons.length === 0) { console.log('No reviewers configured'); return; } - + try { await github.rest.pulls.requestReviewers({ owner: context.repo.owner, From 3d3078e9bff8f6f2845579aca2c84d0cb00cb8ce Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Thu, 26 Mar 2026 20:35:09 +0100 Subject: [PATCH 18/20] Update add-to-project.yaml --- .github/workflows/add-to-project.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/add-to-project.yaml b/.github/workflows/add-to-project.yaml index 315db34a..4e7f3842 100644 --- a/.github/workflows/add-to-project.yaml +++ b/.github/workflows/add-to-project.yaml @@ -55,7 +55,6 @@ jobs: private-key: ${{ secrets.APP_SECRET }} permission-issues: write permission-pull-requests: write - permission-contents: read permission-members: read permission-organization-projects: write permission-administration: write From 4239661476f5043ea26987a10379f80a7706cd8e Mon Sep 17 00:00:00 2001 From: cosimomeli <11272734+cosimomeli@users.noreply.github.com> Date: Fri, 27 Mar 2026 10:55:04 +0000 Subject: [PATCH 19/20] docs(release_notes): update RELEASE_NOTES.md [dependabot skip] --- RELEASE_NOTES.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 1ec3b604..65252169 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,6 +1,6 @@ # GitHub Workflows Release Notes -## 0.0.3-dev - 2026-03-24 +## 0.0.3-dev - 2026-03-27 ### Features @@ -80,6 +80,7 @@ ### Security +- Workflow hardening: check-pr / docker / add-to-project (PR #269 by @chicco785) - Fix trivy action to a secure version (PR #266 by @chicco785) - add-to-project wf: add job to sync priority in projects with labels for Vanta (PR #229 by @chicco785) @@ -87,6 +88,8 @@ ### Dependencies +- Bump dawidd6/action-download-artifact from 18 to 19 (PR #265 by + @dependabot[bot]) - Bump actions/create-github-app-token from 2 to 3 (PR #261 by @dependabot[bot]) - Bump dorny/paths-filter from 3 to 4 (PR #259 by @dependabot[bot]) - Bump docker/login-action from 3 to 4 (PR #262 by @dependabot[bot]) From 2244a660691551106b469479c28d45286368c8a3 Mon Sep 17 00:00:00 2001 From: "Federico M. Facca" Date: Fri, 27 Mar 2026 12:21:32 +0100 Subject: [PATCH 20/20] Update add-to-project.yaml Co-Authored-By: Bot --- .github/workflows/add-to-project.yaml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/workflows/add-to-project.yaml b/.github/workflows/add-to-project.yaml index 7e326830..2ba57b4d 100644 --- a/.github/workflows/add-to-project.yaml +++ b/.github/workflows/add-to-project.yaml @@ -218,12 +218,25 @@ jobs: with: github-token: ${{ steps.generate-token.outputs.token }} script: | - await github.rest.issues.addAssignees({ + // Check if PR already has assignees + const pr = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, - issue_number: context.issue.number, - assignees: [context.payload.pull_request.user.login] + pull_number: context.issue.number }); + + // Only assign PR creator if no assignees exist + if (!pr.data.assignees || pr.data.assignees.length === 0) { + await github.rest.issues.addAssignees({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + assignees: [context.payload.pull_request.user.login] + }); + console.log('Assigned PR creator as assignee'); + } else { + console.log('PR already has assignees, skipping assignment'); + } - name: Add permissions if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == false && steps.add-project.outputs.itemId }} run: |