Skip to content

Commit

Permalink
Enforce permissions for releases and patches
Browse files Browse the repository at this point in the history
TODO: do this for all workflows without deduplicating this code
The right way would be to create a script check_actor_permission.sh
but this script is not checked out in the caller repo. There is no
good workaround
https://github.com/orgs/community/discussions/25289
https://github.com/orgs/community/discussions/25294
https://github.com/orgs/community/discussions/68735
https://github.com/orgs/community/discussions/63863
https://github.com/orgs/community/discussions/123261
The list goes on..

Signed-off-by: HARPER Jon <[email protected]>
  • Loading branch information
jonenst committed Mar 7, 2025
1 parent 4716775 commit 7229b78
Show file tree
Hide file tree
Showing 9 changed files with 270 additions and 0 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/patch-backend-app-generic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ on:
required: false
default: 'release'
type: string
permission:
required: false
default: 'maintain' # "pull" or "triage" or "push" or "maintain" or "admin"
type: string
secrets:
VERSIONBUMP_GHAPP_PRIVATE_KEY:
required: true
Expand All @@ -37,6 +41,32 @@ jobs:
environment:
name: ${{ inputs.environment }}
steps:
# don't allow to disable this check, and for security only succeed if everything goes perfectly and outputs "true"
# TODO deduplicate this code when github actions allows to easily share a script used
# by reusable workflows. Currently only the workflow file is checked out at the caller
# There are no good workarounds to checkout a companion file (script or composite action)
- name: Check Actor Permission
env:
# Need to properly pass permission all the way down to jq as data to avoid script injections
PERMISSION: ${{ inputs.permission }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "checking permission=$PERMISSION on repo=$GITHUB_REPOSITORY for user=$GITHUB_ACTOR"
# no need to escape GITHUB_REPOSITORY and GITHUB_ACTOR because github
# names can only contain ASCII letters, digits, and the characters ., # -, and _.
# permission: legacy, is actually a role (one per user) and doesn't
# have "maintain" role, only ["none", "read", "write", "admin"]
# role_name: one per user, new standard roles, custom roles, "" and
# "push" and "pull" instead of "none" and "read" and "write": "",
# "read", "triage", "write", "maintain", "admin" and also non
# standard custom roles
# user.permissions: boolean status only for each standard permissions "pull", "triage", "push", "maintain", "admin"
# So the best for now is to use user.permissions I think.
# Not using gh --jq gojq because we can't use variables with it and also it automatically removes quotes from strings which could be an attack vector
# the gh api returns a JSON boolean so jq can only output true or false without quotes.
allowed=$(gh api "repos/$GITHUB_REPOSITORY/collaborators/$GITHUB_ACTOR/permission" | jq --arg PERMISSION "$PERMISSION" '.user.permissions[$PERMISSION]')
[[ "$allowed" == "true" ]] || exit 1
- uses: actions/create-github-app-token@v1
id: app-token
name: Generate app token
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/patch-backend-lib-generic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ on:
required: false
default: 'release'
type: string
permission:
required: false
default: 'maintain' # "pull" or "triage" or "push" or "maintain" or "admin"
type: string
secrets:
VERSIONBUMP_GHAPP_PRIVATE_KEY:
required: true
Expand All @@ -22,6 +26,32 @@ jobs:
environment:
name: ${{ inputs.environment }}
steps:
# don't allow to disable this check, and for security only succeed if everything goes perfectly and outputs "true"
# TODO deduplicate this code when github actions allows to easily share a script used
# by reusable workflows. Currently only the workflow file is checked out at the caller
# There are no good workarounds to checkout a companion file (script or composite action)
- name: Check Actor Permission
env:
# Need to properly pass permission all the way down to jq as data to avoid script injections
PERMISSION: ${{ inputs.permission }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "checking permission=$PERMISSION on repo=$GITHUB_REPOSITORY for user=$GITHUB_ACTOR"
# no need to escape GITHUB_REPOSITORY and GITHUB_ACTOR because github
# names can only contain ASCII letters, digits, and the characters ., # -, and _.
# permission: legacy, is actually a role (one per user) and doesn't
# have "maintain" role, only ["none", "read", "write", "admin"]
# role_name: one per user, new standard roles, custom roles, "" and
# "push" and "pull" instead of "none" and "read" and "write": "",
# "read", "triage", "write", "maintain", "admin" and also non
# standard custom roles
# user.permissions: boolean status only for each standard permissions "pull", "triage", "push", "maintain", "admin"
# So the best for now is to use user.permissions I think.
# Not using gh --jq gojq because we can't use variables with it and also it automatically removes quotes from strings which could be an attack vector
# the gh api returns a JSON boolean so jq can only output true or false without quotes.
allowed=$(gh api "repos/$GITHUB_REPOSITORY/collaborators/$GITHUB_ACTOR/permission" | jq --arg PERMISSION "$PERMISSION" '.user.permissions[$PERMISSION]')
[[ "$allowed" == "true" ]] || exit 1
- name: Validate branch name format
run: |
if [[ ! "${{ inputs.branchRef }}" =~ ^release-v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/patch-base-docker-image-generic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ on:
required: false
default: 'release'
type: string
permission:
required: false
default: 'maintain' # "pull" or "triage" or "push" or "maintain" or "admin"
type: string
secrets:
VERSIONBUMP_GHAPP_PRIVATE_KEY:
required: true
Expand All @@ -29,6 +33,32 @@ jobs:
environment:
name: ${{ inputs.environment }}
steps:
# don't allow to disable this check, and for security only succeed if everything goes perfectly and outputs "true"
# TODO deduplicate this code when github actions allows to easily share a script used
# by reusable workflows. Currently only the workflow file is checked out at the caller
# There are no good workarounds to checkout a companion file (script or composite action)
- name: Check Actor Permission
env:
# Need to properly pass permission all the way down to jq as data to avoid script injections
PERMISSION: ${{ inputs.permission }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "checking permission=$PERMISSION on repo=$GITHUB_REPOSITORY for user=$GITHUB_ACTOR"
# no need to escape GITHUB_REPOSITORY and GITHUB_ACTOR because github
# names can only contain ASCII letters, digits, and the characters ., # -, and _.
# permission: legacy, is actually a role (one per user) and doesn't
# have "maintain" role, only ["none", "read", "write", "admin"]
# role_name: one per user, new standard roles, custom roles, "" and
# "push" and "pull" instead of "none" and "read" and "write": "",
# "read", "triage", "write", "maintain", "admin" and also non
# standard custom roles
# user.permissions: boolean status only for each standard permissions "pull", "triage", "push", "maintain", "admin"
# So the best for now is to use user.permissions I think.
# Not using gh --jq gojq because we can't use variables with it and also it automatically removes quotes from strings which could be an attack vector
# the gh api returns a JSON boolean so jq can only output true or false without quotes.
allowed=$(gh api "repos/$GITHUB_REPOSITORY/collaborators/$GITHUB_ACTOR/permission" | jq --arg PERMISSION "$PERMISSION" '.user.permissions[$PERMISSION]')
[[ "$allowed" == "true" ]] || exit 1
- uses: actions/create-github-app-token@v1
id: app-token
name: Generate app token
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/patch-frontend-app-generic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ on:
required: false
default: 'release'
type: string
permission:
required: false
default: 'maintain' # "pull" or "triage" or "push" or "maintain" or "admin"
type: string
secrets:
VERSIONBUMP_GHAPP_PRIVATE_KEY:
required: true
Expand All @@ -37,6 +41,32 @@ jobs:
environment:
name: ${{ inputs.environment }}
steps:
# don't allow to disable this check, and for security only succeed if everything goes perfectly and outputs "true"
# TODO deduplicate this code when github actions allows to easily share a script used
# by reusable workflows. Currently only the workflow file is checked out at the caller
# There are no good workarounds to checkout a companion file (script or composite action)
- name: Check Actor Permission
env:
# Need to properly pass permission all the way down to jq as data to avoid script injections
PERMISSION: ${{ inputs.permission }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "checking permission=$PERMISSION on repo=$GITHUB_REPOSITORY for user=$GITHUB_ACTOR"
# no need to escape GITHUB_REPOSITORY and GITHUB_ACTOR because github
# names can only contain ASCII letters, digits, and the characters ., # -, and _.
# permission: legacy, is actually a role (one per user) and doesn't
# have "maintain" role, only ["none", "read", "write", "admin"]
# role_name: one per user, new standard roles, custom roles, "" and
# "push" and "pull" instead of "none" and "read" and "write": "",
# "read", "triage", "write", "maintain", "admin" and also non
# standard custom roles
# user.permissions: boolean status only for each standard permissions "pull", "triage", "push", "maintain", "admin"
# So the best for now is to use user.permissions I think.
# Not using gh --jq gojq because we can't use variables with it and also it automatically removes quotes from strings which could be an attack vector
# the gh api returns a JSON boolean so jq can only output true or false without quotes.
allowed=$(gh api "repos/$GITHUB_REPOSITORY/collaborators/$GITHUB_ACTOR/permission" | jq --arg PERMISSION "$PERMISSION" '.user.permissions[$PERMISSION]')
[[ "$allowed" == "true" ]] || exit 1
- name: Generate GitHub App Token
id: app-token
uses: actions/create-github-app-token@v1
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/release-backend-app-generic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ on:
required: false
default: 'release'
type: string
permission:
required: false
default: 'maintain' # "pull" or "triage" or "push" or "maintain" or "admin"
type: string
secrets:
VERSIONBUMP_GHAPP_PRIVATE_KEY:
required: true
Expand All @@ -40,6 +44,32 @@ jobs:
environment:
name: ${{ inputs.environment }}
steps:
# don't allow to disable this check, and for security only succeed if everything goes perfectly and outputs "true"
# TODO deduplicate this code when github actions allows to easily share a script used
# by reusable workflows. Currently only the workflow file is checked out at the caller
# There are no good workarounds to checkout a companion file (script or composite action)
- name: Check Actor Permission
env:
# Need to properly pass permission all the way down to jq as data to avoid script injections
PERMISSION: ${{ inputs.permission }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "checking permission=$PERMISSION on repo=$GITHUB_REPOSITORY for user=$GITHUB_ACTOR"
# no need to escape GITHUB_REPOSITORY and GITHUB_ACTOR because github
# names can only contain ASCII letters, digits, and the characters ., # -, and _.
# permission: legacy, is actually a role (one per user) and doesn't
# have "maintain" role, only ["none", "read", "write", "admin"]
# role_name: one per user, new standard roles, custom roles, "" and
# "push" and "pull" instead of "none" and "read" and "write": "",
# "read", "triage", "write", "maintain", "admin" and also non
# standard custom roles
# user.permissions: boolean status only for each standard permissions "pull", "triage", "push", "maintain", "admin"
# So the best for now is to use user.permissions I think.
# Not using gh --jq gojq because we can't use variables with it and also it automatically removes quotes from strings which could be an attack vector
# the gh api returns a JSON boolean so jq can only output true or false without quotes.
allowed=$(gh api "repos/$GITHUB_REPOSITORY/collaborators/$GITHUB_ACTOR/permission" | jq --arg PERMISSION "$PERMISSION" '.user.permissions[$PERMISSION]')
[[ "$allowed" == "true" ]] || exit 1
- uses: actions/create-github-app-token@v1
id: app-token
name: Generate app token
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/release-backend-lib-generic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ on:
required: false
default: 'release'
type: string
permission:
required: false
default: 'maintain' # "pull" or "triage" or "push" or "maintain" or "admin"
type: string
secrets:
VERSIONBUMP_GHAPP_PRIVATE_KEY:
required: true
Expand All @@ -22,6 +26,32 @@ jobs:
environment:
name: ${{ inputs.environment }}
steps:
# don't allow to disable this check, and for security only succeed if everything goes perfectly and outputs "true"
# TODO deduplicate this code when github actions allows to easily share a script used
# by reusable workflows. Currently only the workflow file is checked out at the caller
# There are no good workarounds to checkout a companion file (script or composite action)
- name: Check Actor Permission
env:
# Need to properly pass permission all the way down to jq as data to avoid script injections
PERMISSION: ${{ inputs.permission }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "checking permission=$PERMISSION on repo=$GITHUB_REPOSITORY for user=$GITHUB_ACTOR"
# no need to escape GITHUB_REPOSITORY and GITHUB_ACTOR because github
# names can only contain ASCII letters, digits, and the characters ., # -, and _.
# permission: legacy, is actually a role (one per user) and doesn't
# have "maintain" role, only ["none", "read", "write", "admin"]
# role_name: one per user, new standard roles, custom roles, "" and
# "push" and "pull" instead of "none" and "read" and "write": "",
# "read", "triage", "write", "maintain", "admin" and also non
# standard custom roles
# user.permissions: boolean status only for each standard permissions "pull", "triage", "push", "maintain", "admin"
# So the best for now is to use user.permissions I think.
# Not using gh --jq gojq because we can't use variables with it and also it automatically removes quotes from strings which could be an attack vector
# the gh api returns a JSON boolean so jq can only output true or false without quotes.
allowed=$(gh api "repos/$GITHUB_REPOSITORY/collaborators/$GITHUB_ACTOR/permission" | jq --arg PERMISSION "$PERMISSION" '.user.permissions[$PERMISSION]')
[[ "$allowed" == "true" ]] || exit 1
- name: Validate Version Type
run: |
if [[ ! "${{ inputs.versionType }}" =~ ^(major|minor)$ ]]; then
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/release-base-docker-image-generic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ on:
required: false
default: 'release'
type: string
permission:
required: false
default: 'maintain' # "pull" or "triage" or "push" or "maintain" or "admin"
type: string
secrets:
VERSIONBUMP_GHAPP_PRIVATE_KEY:
required: true
Expand All @@ -32,6 +36,32 @@ jobs:
environment:
name: ${{ inputs.environment }}
steps:
# don't allow to disable this check, and for security only succeed if everything goes perfectly and outputs "true"
# TODO deduplicate this code when github actions allows to easily share a script used
# by reusable workflows. Currently only the workflow file is checked out at the caller
# There are no good workarounds to checkout a companion file (script or composite action)
- name: Check Actor Permission
env:
# Need to properly pass permission all the way down to jq as data to avoid script injections
PERMISSION: ${{ inputs.permission }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "checking permission=$PERMISSION on repo=$GITHUB_REPOSITORY for user=$GITHUB_ACTOR"
# no need to escape GITHUB_REPOSITORY and GITHUB_ACTOR because github
# names can only contain ASCII letters, digits, and the characters ., # -, and _.
# permission: legacy, is actually a role (one per user) and doesn't
# have "maintain" role, only ["none", "read", "write", "admin"]
# role_name: one per user, new standard roles, custom roles, "" and
# "push" and "pull" instead of "none" and "read" and "write": "",
# "read", "triage", "write", "maintain", "admin" and also non
# standard custom roles
# user.permissions: boolean status only for each standard permissions "pull", "triage", "push", "maintain", "admin"
# So the best for now is to use user.permissions I think.
# Not using gh --jq gojq because we can't use variables with it and also it automatically removes quotes from strings which could be an attack vector
# the gh api returns a JSON boolean so jq can only output true or false without quotes.
allowed=$(gh api "repos/$GITHUB_REPOSITORY/collaborators/$GITHUB_ACTOR/permission" | jq --arg PERMISSION "$PERMISSION" '.user.permissions[$PERMISSION]')
[[ "$allowed" == "true" ]] || exit 1
- uses: actions/create-github-app-token@v1
id: app-token
name: Generate app token
Expand Down
Loading

0 comments on commit 7229b78

Please sign in to comment.