diff --git a/.github/workflows/add-good-first-issue-labels.yml b/.github/workflows/add-good-first-issue-labels.yml
index 05d05ca..5ba7a6a 100644
--- a/.github/workflows/add-good-first-issue-labels.yml
+++ b/.github/workflows/add-good-first-issue-labels.yml
@@ -9,15 +9,20 @@ on:
types:
- created
+permissions: {}
+
jobs:
add-labels:
+ name: Add 'Good First Issue' and 'area/*' labels
if: ${{(!github.event.issue.pull_request && github.event.issue.state != 'closed' && github.actor != 'asyncapi-bot') && (contains(github.event.comment.body, '/good-first-issue') || contains(github.event.comment.body, '/gfi' ))}}
runs-on: ubuntu-latest
+ permissions:
+ issues: write # This is needed to add labels to issues.
steps:
- name: Add label
uses: actions/github-script@v7
with:
- github-token: ${{ secrets.GH_TOKEN }}
+ github-token: ${{ github.token }}
script: |
const areas = ['javascript', 'typescript', 'java' , 'go', 'docs', 'ci-cd', 'design'];
const words = context.payload.comment.body.trim().split(" ");
diff --git a/.github/workflows/automerge-for-humans-add-ready-to-merge-or-do-not-merge-label.yml b/.github/workflows/automerge-for-humans-add-ready-to-merge-or-do-not-merge-label.yml
index 2db55d8..99078d3 100644
--- a/.github/workflows/automerge-for-humans-add-ready-to-merge-or-do-not-merge-label.yml
+++ b/.github/workflows/automerge-for-humans-add-ready-to-merge-or-do-not-merge-label.yml
@@ -12,8 +12,15 @@ on:
types:
- created
+permissions: {}
+
jobs:
add-ready-to-merge-label:
+ name: Add ready-to-merge label
+ permissions:
+ issues: write # required to add labels and post comments on PR issues
+ pull-requests: write # required to read PR metadata from the issue pull_request URL
+ contents: read # required to compare PR branch commits against base
if: >
github.event.issue.pull_request &&
github.event.issue.state != 'closed' &&
@@ -30,7 +37,7 @@ jobs:
env:
GITHUB_ACTOR: ${{ github.actor }}
with:
- github-token: ${{ secrets.GH_TOKEN }}
+ github-token: ${{ github.token }}
script: |
const prDetailsUrl = context.payload.issue.pull_request.url;
const { data: pull } = await github.request(prDetailsUrl);
@@ -69,6 +76,10 @@ jobs:
}
add-do-not-merge-label:
+ name: Add do-not-merge label
+ permissions:
+ issues: write # required to add labels on PR issues
+ pull-requests: write # required to read PR metadata from the issue pull_request URL
if: >
github.event.issue.pull_request &&
github.event.issue.state != 'closed' &&
@@ -82,7 +93,7 @@ jobs:
- name: Add do-not-merge label
uses: actions/github-script@v7
with:
- github-token: ${{ secrets.GH_TOKEN }}
+ github-token: ${{ github.token }}
script: |
github.rest.issues.addLabels({
issue_number: context.issue.number,
@@ -91,6 +102,10 @@ jobs:
labels: ['do-not-merge']
})
add-autoupdate-label:
+ name: Add autoupdate label
+ permissions:
+ issues: write # required to add labels on PR issues
+ pull-requests: write # required to read PR metadata from the issue pull_request URL
if: >
github.event.issue.pull_request &&
github.event.issue.state != 'closed' &&
@@ -104,7 +119,7 @@ jobs:
- name: Add autoupdate label
uses: actions/github-script@v7
with:
- github-token: ${{ secrets.GH_TOKEN }}
+ github-token: ${{ github.token }}
script: |
github.rest.issues.addLabels({
issue_number: context.issue.number,
diff --git a/.github/workflows/automerge-for-humans-merging.yml b/.github/workflows/automerge-for-humans-merging.yml
index 482c83d..b47a551 100644
--- a/.github/workflows/automerge-for-humans-merging.yml
+++ b/.github/workflows/automerge-for-humans-merging.yml
@@ -14,16 +14,20 @@ on:
- edited
- ready_for_review
- reopened
- - unlocked
+ - unlocked # zizmor: ignore[dangerous-triggers] needed if we want author to be our bot
+
+permissions: {}
jobs:
automerge-for-humans:
+ name: Automerge PRs labeled with ready-to-merge
+ permissions:
+ contents: read # required for PR commit metadata reads
+ pull-requests: read # required to read pull request details in github-script steps
# it runs only if PR actor is not a bot, at least not a bot that we know
if: |
github.event.pull_request.draft == false &&
- (github.event.pull_request.user.login != 'asyncapi-bot' ||
- github.event.pull_request.user.login != 'dependabot[bot]' ||
- github.event.pull_request.user.login != 'dependabot-preview[bot]')
+ !contains(fromJSON('["asyncapi-bot","dependabot[bot]","dependabot-preview[bot]"]'), github.event.pull_request.user.login)
runs-on: ubuntu-latest
steps:
- name: Get PR authors
@@ -68,9 +72,11 @@ jobs:
- name: Create commit message
id: create-commit-message
uses: actions/github-script@v7
+ env:
+ AUTHORS_JSON: ${{ steps.authors.outputs.result }}
with:
script: |
- const authors = ${{ steps.authors.outputs.result }};
+ const authors = JSON.parse(process.env.AUTHORS_JSON);
if (Object.keys(authors).length === 0) {
core.setFailed('No authors found in the PR');
diff --git a/.github/workflows/automerge-for-humans-remove-ready-to-merge-label-on-edit.yml b/.github/workflows/automerge-for-humans-remove-ready-to-merge-label-on-edit.yml
index d5a290d..d31ed82 100644
--- a/.github/workflows/automerge-for-humans-remove-ready-to-merge-label-on-edit.yml
+++ b/.github/workflows/automerge-for-humans-remove-ready-to-merge-label-on-edit.yml
@@ -6,19 +6,24 @@
name: Remove ready-to-merge label
on:
- pull_request_target:
+ pull_request:
types:
- synchronize
- edited
+permissions: {}
+
jobs:
remove-ready-label:
+ name: Remove ready-to-merge label
runs-on: ubuntu-latest
+ permissions:
+ pull-requests: write # required to remove labels and post comments on PR issues
steps:
- name: Remove label
uses: actions/github-script@v7
with:
- github-token: ${{ secrets.GH_TOKEN }}
+ github-token: ${{ github.token }}
script: |
const labelToRemove = 'ready-to-merge';
const labels = context.payload.pull_request.labels;
diff --git a/.github/workflows/automerge-orphans.yml b/.github/workflows/automerge-orphans.yml
index 23a0b00..cda0740 100644
--- a/.github/workflows/automerge-orphans.yml
+++ b/.github/workflows/automerge-orphans.yml
@@ -7,19 +7,26 @@ on:
schedule:
- cron: "0 0 * * *"
+permissions: {}
+
jobs:
identify-orphans:
if: startsWith(github.repository, 'asyncapi/')
name: Find orphans and notify
+ permissions:
+ contents: read # required by checkout and repository metadata reads
+ pull-requests: read # required to list open pull requests
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- name: Get list of orphans
uses: actions/github-script@v7
id: orphans
with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
+ github-token: ${{ github.token }}
script: |
const query = `query($owner:String!, $name:String!) {
repository(owner:$owner, name:$name){
diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml
index 9faa78b..e81c003 100644
--- a/.github/workflows/automerge.yml
+++ b/.github/workflows/automerge.yml
@@ -4,10 +4,12 @@
name: Automerge PRs from bots
on:
- pull_request_target:
+ pull_request_target: # Needed as GH_TOKEN_BOT_EVE needed for approval.
types:
- opened
- - synchronize
+ - synchronize # zizmor: ignore[dangerous-triggers]
+
+permissions: {}
jobs:
autoapprove-for-bot:
diff --git a/.github/workflows/autoupdate.yml b/.github/workflows/autoupdate.yml
index eeb77a4..30ff788 100644
--- a/.github/workflows/autoupdate.yml
+++ b/.github/workflows/autoupdate.yml
@@ -18,6 +18,8 @@ on:
- 'bot/**'
- 'all-contributors/**'
+permissions: {}
+
jobs:
autoupdate-for-bot:
if: startsWith(github.repository, 'asyncapi/')
@@ -25,7 +27,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Autoupdating
- uses: docker://chinthakagodawita/autoupdate-action:v1
+ uses: chinthakagodawita/autoupdate@0707656cd062a3b0cf8fa9b2cda1d1404d74437e
env:
GITHUB_TOKEN: '${{ secrets.GH_TOKEN_BOT_EVE }}'
PR_FILTER: "labelled"
diff --git a/.github/workflows/bounty-program-commands.yml b/.github/workflows/bounty-program-commands.yml
index c42e300..3447c2e 100644
--- a/.github/workflows/bounty-program-commands.yml
+++ b/.github/workflows/bounty-program-commands.yml
@@ -20,10 +20,16 @@ env:
{"name": "bounty", "color": "0e8a16", "description": "Participation in the Bounty Program"}
]
+permissions: {}
+
jobs:
guard-against-unauthorized-use:
+ name: Guard against unauthorized use
+ permissions:
+ issues: write # required to post a comment on the issue/PR
+ pull-requests: write # required to post a comment on the issue/PR if it's a PR
if: >
- github.actor != ('aeworxet' || 'thulieblack') &&
+ !contains(fromJSON('["aeworxet","thulieblack"]'), github.actor) &&
(
startsWith(github.event.comment.body, '/bounty' )
)
@@ -36,7 +42,7 @@ jobs:
env:
ACTOR: ${{ github.actor }}
with:
- github-token: ${{ secrets.GH_TOKEN }}
+ github-token: ${{ github.token }}
script: |
const commentText = `❌ @${process.env.ACTOR} is not authorized to use the Bounty Program's commands.
These commands can only be used by members of the [Bounty Team](https://github.com/orgs/asyncapi/teams/bounty_team).`;
@@ -50,19 +56,22 @@ jobs:
})
add-label-bounty:
+ name: Add bounty label
+ permissions:
+ issues: write # required to read/create labels and add labels on the issue/PR
+ pull-requests: write # required to read/create labels and add labels on the issue/PR
if: >
- github.actor == ('aeworxet' || 'thulieblack') &&
+ contains(fromJSON('["aeworxet","thulieblack"]'), github.actor) &&
(
startsWith(github.event.comment.body, '/bounty' )
)
runs-on: ubuntu-latest
-
steps:
- name: Add label `bounty`
uses: actions/github-script@v7
with:
- github-token: ${{ secrets.GH_TOKEN }}
+ github-token: ${{ github.token }}
script: |
const BOUNTY_PROGRAM_LABELS = JSON.parse(process.env.BOUNTY_PROGRAM_LABELS_JSON);
let LIST_OF_LABELS_FOR_REPO = await github.rest.issues.listLabelsForRepo({
@@ -91,19 +100,21 @@ jobs:
})
remove-label-bounty:
+ name: Remove bounty label
+ permissions:
+ issues: write # required to read/remove labels on the issue/PR
+ pull-requests: write # required to read/remove labels on the issue/PR if it's a PR
if: >
- github.actor == ('aeworxet' || 'thulieblack') &&
+ contains(fromJSON('["aeworxet","thulieblack"]'), github.actor) &&
(
startsWith(github.event.comment.body, '/unbounty' )
)
-
runs-on: ubuntu-latest
-
steps:
- name: Remove label `bounty`
uses: actions/github-script@v7
with:
- github-token: ${{ secrets.GH_TOKEN }}
+ github-token: ${{ github.token }}
script: |
const BOUNTY_PROGRAM_LABELS = JSON.parse(process.env.BOUNTY_PROGRAM_LABELS_JSON);
let LIST_OF_LABELS_FOR_ISSUE = await github.rest.issues.listLabelsOnIssue({
diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml
index 6228c56..6fe1a13 100644
--- a/.github/workflows/help-command.yml
+++ b/.github/workflows/help-command.yml
@@ -4,21 +4,26 @@
name: Create help comment
on:
- issue_comment:
- types:
- - created
+ issue_comment:
+ types:
+ - created
+
+permissions: {}
jobs:
create_help_comment_pr:
+ name: Help Comment in PR
if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/help') && github.actor != 'asyncapi-bot' }}
runs-on: ubuntu-latest
+ permissions:
+ pull-requests: write # To comment on Pull requests
steps:
- name: Add comment to PR
uses: actions/github-script@v7
env:
ACTOR: ${{ github.actor }}
with:
- github-token: ${{ secrets.GH_TOKEN }}
+ github-token: ${{ github.token }}
script: |
//Yes to add comment to PR the same endpoint is use that we use to create a comment in issue
//For more details http://developer.github.com/v3/issues/comments/
@@ -41,15 +46,18 @@ jobs:
})
create_help_comment_issue:
+ name: Help Comment in Issue
if: ${{ !github.event.issue.pull_request && startsWith(github.event.comment.body, '/help') && github.actor != 'asyncapi-bot' }}
runs-on: ubuntu-latest
+ permissions:
+ issues: write # To comment on Issues
steps:
- name: Add comment to Issue
uses: actions/github-script@v7
env:
ACTOR: ${{ github.actor }}
with:
- github-token: ${{ secrets.GH_TOKEN }}
+ github-token: ${{ github.token }}
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
diff --git a/.github/workflows/if-nodejs-pr-testing.yml b/.github/workflows/if-nodejs-pr-testing.yml
index 2bab0a7..cef2b77 100644
--- a/.github/workflows/if-nodejs-pr-testing.yml
+++ b/.github/workflows/if-nodejs-pr-testing.yml
@@ -8,6 +8,9 @@ on:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
+permissions:
+ contents: read
+
jobs:
test-nodejs-pr:
name: Test NodeJS PR - ${{ matrix.os }}
@@ -18,21 +21,21 @@ jobs:
steps:
- if: >
!github.event.pull_request.draft && !(
- (github.actor == 'asyncapi-bot' && (
+ (github.event.pull_request.user.login == 'asyncapi-bot' && (
startsWith(github.event.pull_request.title, 'ci: update of files from global .github repo') ||
startsWith(github.event.pull_request.title, 'chore(release):')
)) ||
- (github.actor == 'asyncapi-bot-eve' && (
+ (github.event.pull_request.user.login == 'asyncapi-bot-eve' && (
startsWith(github.event.pull_request.title, 'ci: update of files from global .github repo') ||
startsWith(github.event.pull_request.title, 'chore(release):')
)) ||
- (github.actor == 'allcontributors[bot]' &&
+ (github.event.pull_request.user.login == 'allcontributors[bot]' &&
startsWith(github.event.pull_request.title, 'docs: add')
)
)
id: should_run
name: Should Run
- run: echo "shouldrun=true" >> $GITHUB_OUTPUT
+ run: echo "shouldrun=true" >> "$GITHUB_OUTPUT"
shell: bash
- if: steps.should_run.outputs.shouldrun == 'true'
name: Set git to use LF #to once and for all finish neverending fight between Unix and Windows
@@ -43,10 +46,12 @@ jobs:
- if: steps.should_run.outputs.shouldrun == 'true'
name: Checkout repository
uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- if: steps.should_run.outputs.shouldrun == 'true'
name: Check if Node.js project and has package.json
id: packagejson
- run: test -e ./package.json && echo "exists=true" >> $GITHUB_OUTPUT || echo "exists=false" >> $GITHUB_OUTPUT
+ run: test -e ./package.json && echo "exists=true" >> "$GITHUB_OUTPUT" || echo "exists=false" >> "$GITHUB_OUTPUT"
shell: bash
- if: steps.packagejson.outputs.exists == 'true'
name: Determine what node version to use
diff --git a/.github/workflows/issues-prs-notifications.yml b/.github/workflows/issues-prs-notifications.yml
index ce13628..1e3b616 100644
--- a/.github/workflows/issues-prs-notifications.yml
+++ b/.github/workflows/issues-prs-notifications.yml
@@ -9,11 +9,13 @@ on:
types: [opened, reopened]
pull_request_target:
- types: [opened, reopened, ready_for_review]
+ types: [opened, reopened, ready_for_review] # zizmor: ignore[dangerous-triggers]
discussion:
types: [created]
+permissions: {}
+
jobs:
issue:
if: github.event_name == 'issues' && github.actor != 'asyncapi-bot' && github.actor != 'dependabot[bot]' && github.actor != 'dependabot-preview[bot]'
diff --git a/.github/workflows/lint-pr-title.yml b/.github/workflows/lint-pr-title.yml
index 77aa1c6..106f316 100644
--- a/.github/workflows/lint-pr-title.yml
+++ b/.github/workflows/lint-pr-title.yml
@@ -4,32 +4,37 @@
name: Lint PR title
on:
- pull_request_target:
+ pull_request:
types: [opened, reopened, synchronize, edited, ready_for_review]
+permissions: {}
+
jobs:
lint-pr-title:
name: Lint PR title
runs-on: ubuntu-latest
+ permissions:
+ contents: read # To checkout code and read PR information
+ pull-requests: write # To comment on PR if the title is not valid
steps:
# Since this workflow is REQUIRED for a PR to be mergable, we have to have this 'if' statement in step level instead of job level.
- - if: ${{ !contains(fromJson('["asyncapi-bot", "dependabot[bot]", "dependabot-preview[bot]", "allcontributors[bot]"]'), github.actor) }}
+ - if: ${{ !contains(fromJson('["asyncapi-bot", "dependabot[bot]", "dependabot-preview[bot]", "allcontributors[bot]"]'), github.actor) }} # zizmor: ignore[obfuscation]
uses: amannn/action-semantic-pull-request@c3cd5d1ea3580753008872425915e343e351ab54 #version 5.2.0 https://github.com/amannn/action-semantic-pull-request/releases/tag/v5.2.0
id: lint_pr_title
env:
- GITHUB_TOKEN: ${{ secrets.GH_TOKEN}}
+ GITHUB_TOKEN: ${{ github.token }}
with:
subjectPattern: ^(?![A-Z]).+$
subjectPatternError: |
The subject "{subject}" found in the pull request title "{title}" should start with a lowercase character.
# Comments the error message from the above lint_pr_title action
- - if: ${{ always() && steps.lint_pr_title.outputs.error_message != null && !contains(fromJson('["asyncapi-bot", "dependabot[bot]", "dependabot-preview[bot]", "allcontributors[bot]"]'), github.actor)}}
+ - if: ${{ always() && steps.lint_pr_title.outputs.error_message != null && !contains(fromJson('["asyncapi-bot", "dependabot[bot]", "dependabot-preview[bot]", "allcontributors[bot]"]'), github.actor)}} # zizmor: ignore[obfuscation]
name: Comment on PR
uses: marocchino/sticky-pull-request-comment@3d60a5b2dae89d44e0c6ddc69dd7536aec2071cd #use 2.5.0 https://github.com/marocchino/sticky-pull-request-comment/releases/tag/v2.5.0
with:
header: pr-title-lint-error
- GITHUB_TOKEN: ${{ secrets.GH_TOKEN}}
+ GITHUB_TOKEN: ${{ github.token }}
message: |
We require all PRs to follow [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/).
@@ -44,4 +49,4 @@ jobs:
with:
header: pr-title-lint-error
delete: true
- GITHUB_TOKEN: ${{ secrets.GH_TOKEN}}
+ GITHUB_TOKEN: ${{ github.token }}
diff --git a/.github/workflows/notify-tsc-members-mention.yml b/.github/workflows/notify-tsc-members-mention.yml
index ffa39bb..7048d69 100644
--- a/.github/workflows/notify-tsc-members-mention.yml
+++ b/.github/workflows/notify-tsc-members-mention.yml
@@ -17,14 +17,16 @@ on:
types:
- opened
- pull_request_target:
+ pull_request_target: # Needed to access secrets. The checkout is done on base branch so script cannot be malicious.
types:
- - opened
-
+ - opened # zizmor: ignore[dangerous-triggers]
discussion:
types:
- created
+permissions:
+ contents: read # To checkout repository
+
jobs:
issue:
if: github.event_name == 'issues' && contains(github.event.issue.body, '@asyncapi/tsc_members')
@@ -33,6 +35,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@v4
with:
@@ -68,10 +72,11 @@ jobs:
CALENDAR_SERVICE_ACCOUNT: ${{ secrets.CALENDAR_SERVICE_ACCOUNT }}
MAILCHIMP_API_KEY: ${{ secrets.MAILCHIMP_API_KEY }}
TITLE: ${{ github.event.issue.title }}
+ HTML_URL: ${{ github.event.issue.html_url }}
with:
script: |
const sendEmail = require('./.github/workflows/scripts/mailchimp/index.js');
- sendEmail('${{github.event.issue.html_url}}', process.env.TITLE);
+ sendEmail(process.env.HTML_URL, process.env.TITLE);
pull_request:
if: github.event_name == 'pull_request_target' && contains(github.event.pull_request.body, '@asyncapi/tsc_members')
@@ -80,6 +85,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@v4
with:
@@ -115,10 +122,11 @@ jobs:
CALENDAR_SERVICE_ACCOUNT: ${{ secrets.CALENDAR_SERVICE_ACCOUNT }}
MAILCHIMP_API_KEY: ${{ secrets.MAILCHIMP_API_KEY }}
TITLE: ${{ github.event.pull_request.title }}
+ HTML_URL: ${{ github.event.pull_request.html_url }}
with:
script: |
const sendEmail = require('./.github/workflows/scripts/mailchimp/index.js');
- sendEmail('${{github.event.pull_request.html_url}}', process.env.TITLE);
+ sendEmail(process.env.HTML_URL, process.env.TITLE);
discussion:
if: github.event_name == 'discussion' && contains(github.event.discussion.body, '@asyncapi/tsc_members')
@@ -127,6 +135,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@v4
with:
@@ -162,10 +172,11 @@ jobs:
CALENDAR_SERVICE_ACCOUNT: ${{ secrets.CALENDAR_SERVICE_ACCOUNT }}
MAILCHIMP_API_KEY: ${{ secrets.MAILCHIMP_API_KEY }}
TITLE: ${{ github.event.discussion.title }}
+ HTML_URL: ${{ github.event.discussion.html_url }}
with:
script: |
const sendEmail = require('./.github/workflows/scripts/mailchimp/index.js');
- sendEmail('${{github.event.discussion.html_url}}', process.env.TITLE);
+ sendEmail(process.env.HTML_URL, process.env.TITLE);
issue_comment:
if: ${{ github.event_name == 'issue_comment' && !github.event.issue.pull_request && contains(github.event.comment.body, '@asyncapi/tsc_members') }}
@@ -174,6 +185,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@v4
with:
@@ -209,10 +222,11 @@ jobs:
CALENDAR_SERVICE_ACCOUNT: ${{ secrets.CALENDAR_SERVICE_ACCOUNT }}
MAILCHIMP_API_KEY: ${{ secrets.MAILCHIMP_API_KEY }}
TITLE: ${{ github.event.issue.title }}
+ HTML_URL: ${{ github.event.comment.html_url }}
with:
script: |
const sendEmail = require('./.github/workflows/scripts/mailchimp/index.js');
- sendEmail('${{github.event.comment.html_url}}', process.env.TITLE);
+ sendEmail(process.env.HTML_URL, process.env.TITLE);
pr_comment:
if: github.event_name == 'issue_comment' && github.event.issue.pull_request && contains(github.event.comment.body, '@asyncapi/tsc_members')
@@ -221,6 +235,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@v4
with:
@@ -256,10 +272,11 @@ jobs:
CALENDAR_SERVICE_ACCOUNT: ${{ secrets.CALENDAR_SERVICE_ACCOUNT }}
MAILCHIMP_API_KEY: ${{ secrets.MAILCHIMP_API_KEY }}
TITLE: ${{ github.event.issue.title }}
+ HTML_URL: ${{ github.event.comment.html_url }}
with:
script: |
const sendEmail = require('./.github/workflows/scripts/mailchimp/index.js');
- sendEmail('${{github.event.comment.html_url}}', process.env.TITLE);
+ sendEmail(process.env.HTML_URL, process.env.TITLE);
discussion_comment:
if: github.event_name == 'discussion_comment' && contains(github.event.comment.body, '@asyncapi/tsc_members')
@@ -268,6 +285,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@v4
with:
@@ -303,7 +322,8 @@ jobs:
CALENDAR_SERVICE_ACCOUNT: ${{ secrets.CALENDAR_SERVICE_ACCOUNT }}
MAILCHIMP_API_KEY: ${{ secrets.MAILCHIMP_API_KEY }}
TITLE: ${{ github.event.discussion.title }}
+ HTML_URL: ${{ github.event.comment.html_url }}
with:
script: |
const sendEmail = require('./.github/workflows/scripts/mailchimp/index.js');
- sendEmail('${{github.event.comment.html_url}}', process.env.TITLE);
+ sendEmail(process.env.HTML_URL, process.env.TITLE);
diff --git a/.github/workflows/please-take-a-look-command.yml b/.github/workflows/please-take-a-look-command.yml
index 84b5a26..30a6938 100644
--- a/.github/workflows/please-take-a-look-command.yml
+++ b/.github/workflows/please-take-a-look-command.yml
@@ -11,6 +11,8 @@ on:
issue_comment:
types: [created]
+permissions: {}
+
jobs:
ping-for-attention:
if: >
@@ -22,6 +24,7 @@ jobs:
contains(github.event.comment.body, '/ptal') ||
contains(github.event.comment.body, '/PTAL')
)
+ name: Ping code owners for attention
runs-on: ubuntu-latest
steps:
- name: Check for Please Take a Look Command
@@ -31,7 +34,7 @@ jobs:
script: |
const prDetailsUrl = context.payload.issue.pull_request.url;
const { data: pull } = await github.request(prDetailsUrl);
- const reviewers = pull.requested_reviewers.map(reviewer => reviewer.login);
+ const reviewers = (pull.requested_reviewers || []).map(reviewer => reviewer.login);
const { data: reviews } = await github.rest.pulls.listReviews({
owner: context.repo.owner,
diff --git a/.github/workflows/release-announcements.yml b/.github/workflows/release-announcements.yml
index 311b701..b521d39 100644
--- a/.github/workflows/release-announcements.yml
+++ b/.github/workflows/release-announcements.yml
@@ -8,6 +8,9 @@ on:
types:
- published
+permissions:
+ contents: read # To checkout code and read release information
+
jobs:
slack-announce:
@@ -16,6 +19,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- name: Convert markdown to slack markdown for issue
# This workflow is from our own org repo and safe to reference by 'master'.
uses: asyncapi/.github/.github/actions/slackify-markdown@master # //NOSONAR
@@ -42,11 +47,13 @@ jobs:
steps:
- name: Checkout repo
uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- name: Get version of last and previous release
uses: actions/github-script@v7
id: versions
with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
+ github-token: ${{ github.token }}
script: |
const query = `query($owner:String!, $name:String!) {
repository(owner:$owner, name:$name){
@@ -72,12 +79,12 @@ jobs:
env:
PREV_VERSION: ${{steps.versions.outputs.previousver}}
LAST_VERSION: ${{steps.versions.outputs.lastver}}
- run: echo "type=$(npx -q -p semver-diff-cli semver-diff "$PREV_VERSION" "$LAST_VERSION")" >> $GITHUB_OUTPUT
+ run: echo "type=$(npx -q -p semver-diff-cli semver-diff "$PREV_VERSION" "$LAST_VERSION")" >> "$GITHUB_OUTPUT"
- name: Get name of the person that is behind the newly released version
id: author
run: |
AUTHOR_NAME=$(git log -1 --pretty=format:'%an')
- printf 'name=%s\n' "$AUTHOR_NAME" >> $GITHUB_OUTPUT
+ printf 'name=%s\n' "$AUTHOR_NAME" >> "$GITHUB_OUTPUT"
- name: Publish information about the release to Twitter # tweet only if detected version change is not a patch
# tweet goes out even if the type is not major or minor but "You need provide version number to compare."
# it is ok, it just means we did not identify previous version as we are tweeting out information about the release for the first time
diff --git a/.github/workflows/scripts/mailchimp/htmlContent.js b/.github/workflows/scripts/mailchimp/htmlContent.js
index d132c72..e0c8ef6 100644
--- a/.github/workflows/scripts/mailchimp/htmlContent.js
+++ b/.github/workflows/scripts/mailchimp/htmlContent.js
@@ -2,7 +2,24 @@
* This code is centrally managed in https://github.com/asyncapi/.github/
* Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo
*/
+
+/**
+ * Escape HTML special characters to prevent XSS
+ */
+function escapeHtml(text) {
+ if (!text) return '';
+ return text
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''');
+}
+
module.exports = (link, title) => {
+ // Sanitize inputs to prevent XSS
+ const safeLink = escapeHtml(link);
+ const safeTitle = escapeHtml(title);
return `
@@ -386,7 +403,7 @@ There is a new topic at AsyncAPI Initiative that requires Technical Steering Com
Please have a look if it is just something you need to be aware of, or maybe your vote is needed.
-Topic: ${ title }.
+Topic: ${ safeTitle }.
diff --git a/.github/workflows/scripts/mailchimp/index.js b/.github/workflows/scripts/mailchimp/index.js
index 4a200c6..b5147bf 100644
--- a/.github/workflows/scripts/mailchimp/index.js
+++ b/.github/workflows/scripts/mailchimp/index.js
@@ -6,6 +6,12 @@ const mailchimp = require('@mailchimp/mailchimp_marketing');
const core = require('@actions/core');
const htmlContent = require('./htmlContent.js');
+function formatMailchimpError(error) {
+ const status = error?.status || error?.response?.status;
+ const message = error?.message || error?.response?.body?.title || 'Unknown error';
+ return status ? `${ message } (status: ${ status })` : message;
+}
+
/**
* Sending API request to mailchimp to schedule email to subscribers
* Input is the URL to issue/discussion or other resource
@@ -14,6 +20,28 @@ module.exports = async (link, title) => {
let newCampaign;
+ // Validate inputs to prevent injection attacks
+ if (!link || typeof link !== 'string' || link.length > 2000) {
+ return core.setFailed('Invalid link parameter');
+ }
+ if (!title || typeof title !== 'string' || title.length > 500) {
+ return core.setFailed('Invalid title parameter');
+ }
+
+ let parsedLink;
+ try {
+ parsedLink = new URL(link);
+ } catch (error) {
+ return core.setFailed('Invalid link parameter');
+ }
+
+ if (parsedLink.protocol !== 'https:') {
+ return core.setFailed('Link must use https protocol');
+ }
+
+ // Sanitize title by removing control characters and limiting length
+ const sanitizedTitle = title.replace(/[\x00-\x1F\x7F]/g, '').substring(0, 250);
+
mailchimp.setConfig({
apiKey: process.env.MAILCHIMP_API_KEY,
server: 'us12'
@@ -38,7 +66,7 @@ module.exports = async (link, title) => {
}
},
settings: {
- subject_line: `TSC attention required: ${ title }`,
+ subject_line: `TSC attention required: ${ sanitizedTitle }`,
preview_text: 'Check out the latest topic that TSC members have to be aware of',
title: `New topic info - ${ new Date(Date.now()).toUTCString()}`,
from_name: 'AsyncAPI Initiative',
@@ -46,16 +74,16 @@ module.exports = async (link, title) => {
}
});
} catch (error) {
- return core.setFailed(`Failed creating campaign: ${ JSON.stringify(error) }`);
+ return core.setFailed(`Failed creating campaign: ${ formatMailchimpError(error) }`);
}
/*
* Content of the email is added separately after campaign creation
*/
try {
- await mailchimp.campaigns.setContent(newCampaign.id, { html: htmlContent(link, title) });
+ await mailchimp.campaigns.setContent(newCampaign.id, { html: htmlContent(parsedLink.toString(), sanitizedTitle) });
} catch (error) {
- return core.setFailed(`Failed adding content to campaign: ${ JSON.stringify(error) }`);
+ return core.setFailed(`Failed adding content to campaign: ${ formatMailchimpError(error) }`);
}
/*
@@ -72,7 +100,7 @@ module.exports = async (link, title) => {
schedule_time: scheduleDate.toISOString(),
});
} catch (error) {
- return core.setFailed(`Failed scheduling email: ${ JSON.stringify(error) }`);
+ return core.setFailed(`Failed scheduling email: ${ formatMailchimpError(error) }`);
}
core.info(`New email campaign created`);
diff --git a/.github/workflows/stale-issues-prs.yml b/.github/workflows/stale-issues-prs.yml
index 25bee82..e76a36b 100644
--- a/.github/workflows/stale-issues-prs.yml
+++ b/.github/workflows/stale-issues-prs.yml
@@ -7,15 +7,21 @@ on:
schedule:
- cron: "0 0 * * *"
+permissions: {}
+
jobs:
stale:
if: startsWith(github.repository, 'asyncapi/')
name: Mark issue or PR as stale
runs-on: ubuntu-latest
+ permissions:
+ contents: read # As delete-branch is not being used
+ issues: write # To add comments and labels to issues
+ pull-requests: write # To add comments and labels to PRs
steps:
- uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 #v9.1.0 but pointing to commit for security reasons
with:
- repo-token: ${{ secrets.GITHUB_TOKEN }}
+ repo-token: ${{ github.token }}
stale-issue-message: |
This issue has been automatically marked as stale because it has not had recent activity :sleeping:
diff --git a/.github/workflows/transfer-issue.yml b/.github/workflows/transfer-issue.yml
deleted file mode 100644
index dbe84ca..0000000
--- a/.github/workflows/transfer-issue.yml
+++ /dev/null
@@ -1,62 +0,0 @@
-# This action is centrally managed in https://github.com/asyncapi/.github/
-# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo
-
-name: Transfer Issues between repositories
-
-on:
- issue_comment:
- types:
- - created
-
-permissions:
- issues: write
-
-jobs:
- transfer:
- if: ${{(!github.event.issue.pull_request && github.event.issue.state != 'closed' && github.actor != 'asyncapi-bot') && (startsWith(github.event.comment.body, '/transfer-issue') || startsWith(github.event.comment.body, '/ti'))}}
- runs-on: ubuntu-latest
- steps:
- - name: Checkout Repository
- uses: actions/checkout@v4
- - name: Extract Input
- id: extract_step
- env:
- COMMENT: "${{ github.event.comment.body }}"
- run: |
- REPO=$(echo "$COMMENT" | awk '{print $2}')
- echo "repo=$REPO" >> $GITHUB_OUTPUT
- - name: Check Repo
- uses: actions/github-script@v7
- with:
- github-token: ${{secrets.GH_TOKEN}}
- script: |
- const r = "${{github.repository}}"
- const [owner, repo] = r.split('/')
- const repoToMove = process.env.REPO_TO_MOVE
- const issue_number = context.issue.number
- try {
- const {data} = await github.rest.repos.get({
- owner,
- repo: repoToMove
- })
- }catch (e) {
- const body = `${repoToMove} is not a repo under ${owner}. You can only transfer issue to repos that belong to the same organization.`
- await github.rest.issues.createComment({
- owner,
- repo,
- issue_number,
- body
- })
- process.exit(1)
- }
- env:
- REPO_TO_MOVE: ${{steps.extract_step.outputs.repo}}
- - name: Transfer Issue
- id: transferIssue
- working-directory: ./
- run: |
- gh issue transfer "$ISSUE_NUMBER" "asyncapi/$REPO_NAME"
- env:
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- ISSUE_NUMBER: ${{ github.event.issue.number }}
- REPO_NAME: ${{ steps.extract_step.outputs.repo }}
diff --git a/.github/workflows/update-maintainers-trigger.yaml b/.github/workflows/update-maintainers-trigger.yaml
index 12fc4ab..0535e39 100644
--- a/.github/workflows/update-maintainers-trigger.yaml
+++ b/.github/workflows/update-maintainers-trigger.yaml
@@ -13,6 +13,9 @@ on:
- '.github/CODEOWNERS'
- '.docs/CODEOWNERS'
+permissions:
+ contents: read # Just to limit GITHUB_TOKEN as we use GH_TOKEN only
+
jobs:
trigger-maintainers-update:
name: Trigger updating MAINTAINERS.yaml because of CODEOWNERS change
diff --git a/.github/workflows/update-pr.yml b/.github/workflows/update-pr.yml
index 2fa19b0..285c02d 100644
--- a/.github/workflows/update-pr.yml
+++ b/.github/workflows/update-pr.yml
@@ -9,12 +9,16 @@
name: Update PR branches from fork
+permissions:
+ contents: read
+
on:
issue_comment:
types: [created]
jobs:
update-pr:
+ name: Update the fork PR with upstream changes
if: >
startsWith(github.repository, 'asyncapi/') &&
github.event.issue.pull_request &&
@@ -23,12 +27,16 @@ jobs:
contains(github.event.comment.body, '/u')
)
runs-on: ubuntu-latest
+ permissions:
+ issues: write # Required to read PR details and post comments on the PR
+ pull-requests: write # Required to update the PR branch
+ contents: read
steps:
- name: Get Pull Request Details
id: pr
uses: actions/github-script@v7
with:
- github-token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}
+ github-token: ${{ secrets.GH_TOKEN || github.token }}
previews: 'merge-info-preview' # https://docs.github.com/en/graphql/overview/schema-previews#merge-info-preview-more-detailed-information-about-a-pull-requests-merge-state-preview
script: |
const prNumber = context.payload.issue.number;
@@ -40,7 +48,7 @@ jobs:
});
// If the PR has conflicts, we don't want to update it
- const updateable = ['behind', 'blocked', 'unknown', 'draft', 'clean'].includes(pr.mergeable_state);
+ const updateable = ['behind', 'blocked', 'unknown', 'draft', 'clean', 'unstable'].includes(pr.mergeable_state);
console.log(`PR #${prNumber} is ${pr.mergeable_state} and is ${updateable ? 'updateable' : 'not updateable'}`);
core.setOutput('updateable', updateable);
@@ -54,8 +62,10 @@ jobs:
- name: Update the Pull Request
if: steps.pr.outputs.updateable == 'true'
uses: actions/github-script@v7
+ env:
+ PR_DETAILS: ${{ steps.pr.outputs.result }}
with:
- github-token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}
+ github-token: ${{ secrets.GH_TOKEN || github.token }}
script: |
const mutation = `mutation update($input: UpdatePullRequestBranchInput!) {
updatePullRequestBranch(input: $input) {
@@ -65,7 +75,7 @@ jobs:
}
}`;
- const pr_details = ${{ steps.pr.outputs.result }};
+ const pr_details = JSON.parse(process.env.PR_DETAILS);
try {
const { data } = await github.graphql(mutation, {
diff --git a/.github/workflows/welcome-first-time-contrib.yml b/.github/workflows/welcome-first-time-contrib.yml
index 2614d8d..49c761b 100644
--- a/.github/workflows/welcome-first-time-contrib.yml
+++ b/.github/workflows/welcome-first-time-contrib.yml
@@ -4,22 +4,30 @@
name: Welcome first time contributors
on:
- pull_request_target:
+ pull_request:
types:
- opened
issues:
types:
- opened
+permissions:
+ issues: read # Required to check if the issue is the user's first contribution
+ pull-requests: read # Required to check if the pull request is the user's first contribution
+
jobs:
welcome:
name: Post welcome message
- if: ${{ !contains(fromJson('["asyncapi-bot", "dependabot[bot]", "dependabot-preview[bot]", "allcontributors[bot]"]'), github.actor) }}
+ if: ${{ !contains(fromJson('["asyncapi-bot", "dependabot[bot]", "dependabot-preview[bot]", "allcontributors[bot]"]'), github.actor) }} # zizmor: ignore[obfuscation]
runs-on: ubuntu-latest
+ permissions:
+ contents: read # Required to read repository data for checking if it's the user's first contribution
+ issues: write # Required to post welcome message on issues
+ pull-requests: write # Required to post welcome message on pull requests
steps:
- uses: actions/github-script@v7
with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
+ github-token: ${{ github.token }}
script: |
const issueMessage = `Welcome to AsyncAPI. Thanks a lot for reporting your first issue. Please check out our [contributors guide](https://github.com/asyncapi/community/blob/master/CONTRIBUTING.md) and the instructions about a [basic recommended setup](https://github.com/asyncapi/community/blob/master/git-workflow.md) useful for opening a pull request.
Keep in mind there are also other channels you can use to interact with AsyncAPI community. For more details check out [this issue](https://github.com/asyncapi/asyncapi/issues/115).`;
const prMessage = `Welcome to AsyncAPI. Thanks a lot for creating your first pull request. Please check out our [contributors guide](https://github.com/asyncapi/community/blob/master/CONTRIBUTING.md) useful for opening a pull request.
Keep in mind there are also other channels you can use to interact with AsyncAPI community. For more details check out [this issue](https://github.com/asyncapi/asyncapi/issues/115).`;