Skip to content

Bootstrap

Bootstrap #124

Workflow file for this run

name: Bootstrap
# Perform initial project setup to enable development of a new service
on:
workflow_dispatch:
inputs:
issue_number:
description: Issue number (e.g. PI-123)
required: true
type: string
project_name:
description: Project name
required: true
type: string
project_template:
description: Project template
required: true
type: choice
default: message-listener-with-api-client
options:
- api-client-and-server
- api-server
- message-listener
- message-listener-with-api-client
- message-listener-with-api-client-and-server
- 'No template - I want to create the project from scratch'
create_sentry_project:
description: Will the service use Sentry for capturing exceptions?
default: true
required: true
type: boolean
create_oauth_client:
description: Will the service consume another HTTP API that requires HMPPS Auth client credentials?
default: true
required: true
type: boolean
create_ingress:
description: Will the service provide a HTTP API?
default: false
required: true
type: boolean
create_queue:
description: Will the service consume HMPPS domain event messages?
default: true
required: true
type: boolean
create_infra:
description: Will the service be deployed to MOJ Cloud Platform?
default: true
required: true
type: boolean
jobs:
auth-setup:
runs-on: ubuntu-latest
if: ${{ inputs.create_oauth_client }}
steps:
- uses: actions/checkout@v4
- name: Create issue for manual steps
run: |
gh issue create \
--title "${{ inputs.issue_number }} Request HMPPS Auth client for ${{ inputs.project_name }}" \
--body '
- [ ] Clone Jira ticket: [HAAR-1662](https://dsdmoj.atlassian.net/browse/HAAR-1662)
- [ ] Raise in Slack: [#hmpps-auth-audit-registers](https://mojdt.slack.com/archives/C02S71KUBED)' \
--label bootstrap
env:
GITHUB_TOKEN: ${{ github.token }}
project-setup:
if: ${{ inputs.project_template != 'No template - I want to create the project from scratch' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.BOT_GITHUB_TOKEN }}
- name: Render project template
uses: ./.github/actions/render-project-template
with:
project_name: ${{ inputs.project_name }}
project_template: ${{ inputs.project_template }}
- name: Create pull request
id: pr
uses: ./.github/actions/create-signed-pull-request
with:
add-paths: |
settings.gradle.kts
.github/workflows
.idea/runConfigurations
doc/tech-docs
projects/${{ inputs.project_name }}
branch: bootstrap/${{ inputs.project_name }}
commit-message: ${{ inputs.issue_number }} Create initial project for ${{ inputs.project_name }}
private-key: ${{ secrets.BOT_GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.BOT_GPG_PASSPHRASE }}
token: ${{ secrets.BOT_GITHUB_TOKEN }}
- uses: actions/checkout@v4
with:
path: hmpps-probation-integration-e2e-tests
repository: ministryofjustice/hmpps-probation-integration-e2e-tests
token: ${{ secrets.BOT_GITHUB_TOKEN }}
- name: Update e2e test repo
run: sed -i '/add new projects here/i \ - '"'"'["${{ inputs.project_name }}"]'"'"'' hmpps-probation-integration-e2e-tests/.github/workflows/test-single-project.yml
- name: Create pull request
id: e2e-pr
uses: ./.github/actions/create-signed-pull-request
with:
path: hmpps-probation-integration-e2e-tests
add-paths: .github/workflows
branch: ${{ inputs.issue_number }}-create-${{ inputs.project_name }}-project
commit-message: ${{ inputs.issue_number }} Add option to run tests for ${{ inputs.project_name }}
private-key: ${{ secrets.BOT_GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.BOT_GPG_PASSPHRASE }}
token: ${{ secrets.BOT_GITHUB_TOKEN }}
- name: Create issue for manual steps
run: |
gh issue create \
--title "${{ inputs.issue_number }} Complete project setup for ${{ inputs.project_name }}" \
--body '
- [ ] Merge project pull request: ${{ steps.pr.outputs.pull-request-url }}
- [ ] Merge e2e tests pull request: ${{ steps.e2e-pr.outputs.pull-request-url }}' \
--label bootstrap
env:
GITHUB_TOKEN: ${{ github.token }}
sentry-setup:
runs-on: ubuntu-latest
if: ${{ inputs.create_sentry_project }}
outputs:
project_slug: ${{ steps.project.outputs.slug }}
steps:
- uses: actions/checkout@v4
- name: Create project
id: project
run: |
response=$(curl https://sentry.io/api/0/teams/ministryofjustice/probation-integration/projects/ --fail \
-H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
-H 'Content-Type: application/json' --data '{"name":"${{ inputs.project_name }}"}')
echo "slug=$(echo "$response" | jq -r '.slug')" | tee -a "$GITHUB_OUTPUT"
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
- name: Set platform to Kotlin
run: |
curl -X PUT "https://sentry.io/api/0/projects/ministryofjustice/$SLUG/" --fail \
-H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
-H 'Content-Type: application/json' --data '{"platform":"kotlin"}'
env:
SLUG: ${{ steps.project.outputs.slug }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
- name: Get client key id
id: client_key
run: |
response=$(curl "https://sentry.io/api/0/projects/ministryofjustice/$SLUG/keys/" --fail \
-H "Authorization: Bearer $SENTRY_AUTH_TOKEN")
echo "id=$(echo "$response" | jq -r '.[0].id')" | tee -a "$GITHUB_OUTPUT"
env:
SLUG: ${{ steps.project.outputs.slug }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
- name: Set rate limit (10/minute)
run: |
curl -X PUT "https://sentry.io/api/0/projects/ministryofjustice/$SLUG/keys/$KEY_ID/" --fail \
-H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
-H 'Content-Type: application/json' --data '{"rateLimit":{"count":10,"window":60}}'
env:
SLUG: ${{ steps.project.outputs.slug }}
KEY_ID: ${{ steps.client_key.outputs.id }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
- name: Create alert for new issues
run: |
curl "https://sentry.io/api/0/projects/ministryofjustice/$SLUG/rules/?duplicateRule=true&wizardV3=true" --fail \
-H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
-H 'Content-Type: application/json' --data "$(jq --arg env "$env" --arg project_slug "$SLUG" -n '{
"actionMatch": "any",
"actions": [
{
"channel": "probation-integration-notifications",
"channel_id": "C033HPR0W91",
"id": "sentry.integrations.slack.notify_action.SlackNotifyServiceAction",
"name": "Send a notification to the MOJ Digital & Technology Slack workspace to probation-integration-notifications (optionally, an ID: C033HPR0W91) and show tags [] in notification",
"tags": "environment",
"workspace": "50134"
}
],
"conditions": [
{ "id": "sentry.rules.conditions.first_seen_event.FirstSeenEventCondition", "name": "A new issue is created" },
{ "id": "sentry.rules.conditions.regression_event.RegressionEventCondition", "name": "The issue changes state from resolved to unresolved" },
{ "id": "sentry.rules.conditions.reappeared_event.ReappearedEventCondition", "name": "The issue changes state from ignored to unresolved" }
],
"environment": null,
"filterMatch": "all",
"filters": [],
"frequency": 5,
"name": "New issues",
"owner": "team:1611212",
"projects": [$project_slug]
}')"
env:
SLUG: ${{ steps.project.outputs.slug }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
- name: Create alerts for high throughput
run: |
curl "https://sentry.io/api/0/organizations/ministryofjustice/alert-rules/?duplicateRule=true&wizardV3=true" --fail \
-H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
-H 'Content-Type: application/json' --data "$(jq --arg project_slug "$SLUG" --arg project_name "$PROJECT_NAME" -n '{
"aggregate": "count()",
"alertType": "throughput",
"comparisonDelta": 10080,
"dataset": "generic_metrics",
"environment": null,
"eventTypes": [
"transaction"
],
"name": ($project_name + " throughput"),
"owner": "team:1611212",
"projects": [
$project_slug
],
"query": "",
"queryType": 1,
"resolveThreshold": null,
"thresholdPeriod": 1,
"thresholdType": 0,
"timeWindow": 1440,
"triggers": [
{
"actions": [],
"alertThreshold": 500,
"label": "critical"
},
{
"actions": [
{
"inputChannelId": "C033HPR0W91",
"integrationId": 50134,
"options": null,
"targetIdentifier": "#probation-integration-notifications",
"targetType": "specific",
"type": "slack"
}
],
"alertThreshold": 200,
"label": "warning"
}
]
}')"
env:
SLUG: ${{ steps.project.outputs.slug }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
PROJECT_NAME: ${{ inputs.project_name }}
sentry-secrets:
runs-on: ubuntu-latest
if: ${{ inputs.create_sentry_project }}
needs: sentry-setup
strategy:
matrix:
environment: [ "test", "preprod", "prod" ]
environment: ${{ matrix.environment }}
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/cloud-platform-auth
with:
api: ${{ secrets.KUBE_ENV_API }}
cert: ${{ secrets.KUBE_CERT }}
cluster: ${{ secrets.KUBE_CLUSTER }}
namespace: ${{ secrets.KUBE_NAMESPACE }}
token: ${{ secrets.KUBE_TOKEN }}
- name: Get client key DSN
id: client_key
run: |
response=$(curl "https://sentry.io/api/0/projects/ministryofjustice/$SLUG/keys/" --fail \
-H "Authorization: Bearer $SENTRY_AUTH_TOKEN")
dsn=$(echo "$response" | jq -r '.[0].dsn.public')
echo "::add-mask::$dsn"
echo "dsn=$dsn" | tee -a "$GITHUB_OUTPUT"
env:
SLUG: ${{ needs.sentry-setup.outputs.project_slug }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
- name: Store DSN as Kubernetes secret
run: kubectl create secret generic "$PROJECT-sentry" --from-literal "SENTRY_DSN=$VALUE" --from-literal "SENTRY_AUTH_TOKEN=$SENTRY_AUTH_TOKEN"
env:
PROJECT: ${{ inputs.project_name }}
VALUE: ${{ steps.client_key.outputs.dsn }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
sqs-queue-setup:
runs-on: ubuntu-latest
if: ${{ inputs.create_queue }}
steps:
- id: project_name
run: echo "with_underscores_uppercase=$(echo '${{ inputs.project_name }}' | sed 's/-/_/g' | tr '[:lower:]' '[:upper:]')" | tee -a "$GITHUB_OUTPUT"
- uses: actions/checkout@v4
with:
token: ${{ secrets.BOT_GITHUB_TOKEN }}
- uses: actions/checkout@v4
with:
path: cloud-platform-environments-dev
repository: ministryofjustice/cloud-platform-environments
token: ${{ secrets.BOT_GITHUB_EXTERNAL_REPOS_TOKEN }}
- uses: actions/checkout@v4
with:
path: cloud-platform-environments-preprod
repository: ministryofjustice/cloud-platform-environments
token: ${{ secrets.BOT_GITHUB_EXTERNAL_REPOS_TOKEN }}
- uses: actions/checkout@v4
with:
path: cloud-platform-environments-prod
repository: ministryofjustice/cloud-platform-environments
token: ${{ secrets.BOT_GITHUB_EXTERNAL_REPOS_TOKEN }}
- name: Render Terraform queue template
run: |
sed 's/SERVICE_NAME_UPPERCASE/${{ steps.project_name.outputs.with_underscores_uppercase }}/g;s/SERVICE_NAME/${{ inputs.project_name }}/g' templates/sqs.tf > 'cloud-platform-environments-dev/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-dev/resources/${{ inputs.project_name }}-queue.tf'
sed 's/SERVICE_NAME_UPPERCASE/${{ steps.project_name.outputs.with_underscores_uppercase }}/g;s/SERVICE_NAME/${{ inputs.project_name }}/g' templates/sqs.tf > 'cloud-platform-environments-preprod/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-preprod/resources/${{ inputs.project_name }}-queue.tf'
sed 's/SERVICE_NAME_UPPERCASE/${{ steps.project_name.outputs.with_underscores_uppercase }}/g;s/SERVICE_NAME/${{ inputs.project_name }}/g' templates/sqs.tf > 'cloud-platform-environments-prod/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-prod/resources/${{ inputs.project_name }}-queue.tf'
- name: Update IAM access to queues
run: |
sed -i '/queue = \[/a \ module.${{ inputs.project_name }}-queue,' 'cloud-platform-environments-dev/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-dev/resources/iam.tf'
sed -i '/queue = \[/a \ module.${{ inputs.project_name }}-queue,' 'cloud-platform-environments-preprod/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-preprod/resources/iam.tf'
sed -i '/queue = \[/a \ module.${{ inputs.project_name }}-queue,' 'cloud-platform-environments-prod/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-prod/resources/iam.tf'
sed -i '/dlq = \[/a \ module.${{ inputs.project_name }}-dlq,' 'cloud-platform-environments-dev/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-dev/resources/iam.tf'
sed -i '/dlq = \[/a \ module.${{ inputs.project_name }}-dlq,' 'cloud-platform-environments-preprod/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-preprod/resources/iam.tf'
sed -i '/dlq = \[/a \ module.${{ inputs.project_name }}-dlq,' 'cloud-platform-environments-prod/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-prod/resources/iam.tf'
- name: Create dev pull request
id: dev-pr
uses: ./.github/actions/create-signed-pull-request
with:
path: cloud-platform-environments-dev
add-paths: namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-dev
branch: ${{ inputs.issue_number }}-create-${{ inputs.project_name }}-queue-dev
commit-message: ${{ inputs.issue_number }} Create SQS queues for ${{ inputs.project_name }} (dev)
private-key: ${{ secrets.BOT_GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.BOT_GPG_PASSPHRASE }}
token: ${{ secrets.BOT_GITHUB_EXTERNAL_REPOS_TOKEN }}
- name: Create preprod pull request
id: preprod-pr
uses: ./.github/actions/create-signed-pull-request
with:
path: cloud-platform-environments-preprod
add-paths: namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-preprod
branch: ${{ inputs.issue_number }}-create-${{ inputs.project_name }}-queue-preprod
commit-message: ${{ inputs.issue_number }} Create SQS queues for ${{ inputs.project_name }} (preprod)
private-key: ${{ secrets.BOT_GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.BOT_GPG_PASSPHRASE }}
token: ${{ secrets.BOT_GITHUB_EXTERNAL_REPOS_TOKEN }}
- name: Create prod pull request
id: prod-pr
uses: ./.github/actions/create-signed-pull-request
with:
path: cloud-platform-environments-prod
add-paths: namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-prod
branch: ${{ inputs.issue_number }}-create-${{ inputs.project_name }}-queue-prod
commit-message: ${{ inputs.issue_number }} Create SQS queues for ${{ inputs.project_name }} (prod)
private-key: ${{ secrets.BOT_GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.BOT_GPG_PASSPHRASE }}
token: ${{ secrets.BOT_GITHUB_EXTERNAL_REPOS_TOKEN }}
- name: Create issue for manual steps
run: |
gh issue create \
--title '${{ inputs.issue_number }} Complete queue setup for ${{ inputs.project_name }}' \
--body '
- [ ] Enter the event types the service will consume into the filter_policy for dev: [Edit file](https://github.com/ministryofjustice/cloud-platform-environments/edit/${{ inputs.issue_number }}-create-${{ inputs.project_name }}-queue-dev/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-dev/resources/${{ inputs.project_name }}-queue.tf)
- [ ] Enter the event types the service will consume into the filter_policy for preprod: [Edit file](https://github.com/ministryofjustice/cloud-platform-environments/edit/${{ inputs.issue_number }}-create-${{ inputs.project_name }}-queue-preprod/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-preprod/resources/${{ inputs.project_name }}-queue.tf)
- [ ] Enter the event types the service will consume into the filter_policy for prod: [Edit file](https://github.com/ministryofjustice/cloud-platform-environments/edit/${{ inputs.issue_number }}-create-${{ inputs.project_name }}-queue-prod/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-prod/resources/${{ inputs.project_name }}-queue.tf)
- [ ] Request approval in [#ask-cloud-platform](https://mojdt.slack.com/archives/C57UPMZLY)
> ${{ steps.dev-pr.outputs.pull-request-url }}
> ${{ steps.preprod-pr.outputs.pull-request-url }}
> ${{ steps.prod-pr.outputs.pull-request-url }}
- [ ] Merge the pull requests' \
--label bootstrap
env:
GITHUB_TOKEN: ${{ github.token }}
infra-setup:
runs-on: ubuntu-latest
if: ${{ inputs.create_infra }}
steps:
- id: project_name
run: echo "hash=$(echo -n '${{ inputs.project_name }}' | sha1sum | head -c 8)" | tee -a "$GITHUB_OUTPUT"
- uses: actions/checkout@v4
with:
token: ${{ secrets.BOT_GITHUB_TOKEN }}
- uses: actions/checkout@v4
with:
path: cloud-platform-environments-dev
repository: ministryofjustice/cloud-platform-environments
token: ${{ secrets.BOT_GITHUB_EXTERNAL_REPOS_TOKEN }}
- uses: actions/checkout@v4
with:
path: cloud-platform-environments-preprod
repository: ministryofjustice/cloud-platform-environments
token: ${{ secrets.BOT_GITHUB_EXTERNAL_REPOS_TOKEN }}
- uses: actions/checkout@v4
with:
path: cloud-platform-environments-prod
repository: ministryofjustice/cloud-platform-environments
token: ${{ secrets.BOT_GITHUB_EXTERNAL_REPOS_TOKEN }}
- name: Add Pingdom check
run: sed -i '/add new projects here/i \ "${{ inputs.project_name }}",' 'cloud-platform-environments-prod/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-prod/resources/pingdom.tf'
- name: Render certificate templates
run: |
sed 's/$SERVICE_NAME/${{ inputs.project_name }}/g;s/$SERVICE_URL/${{ inputs.project_name }}-dev.hmpps.service.justice.gov.uk/g;s/$SERVICE_SHORT_URL/${{ steps.project_name.outputs.hash }}-dev.hmpps.service.justice.gov.uk/g;s/$ENV/dev/g' templates/certificate.yml >> 'cloud-platform-environments-dev/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-dev/05-certificates.yml'
sed 's/$SERVICE_NAME/${{ inputs.project_name }}/g;s/$SERVICE_URL/${{ inputs.project_name }}-preprod.hmpps.service.justice.gov.uk/g;s/$SERVICE_SHORT_URL/${{ steps.project_name.outputs.hash }}-preprod.hmpps.service.justice.gov.uk/g;s/$ENV/preprod/g' templates/certificate.yml >> 'cloud-platform-environments-preprod/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-preprod/05-certificates.yml'
sed 's/$SERVICE_NAME/${{ inputs.project_name }}/g;s/$SERVICE_URL/${{ inputs.project_name }}.hmpps.service.justice.gov.uk/g;s/$SERVICE_SHORT_URL/${{ steps.project_name.outputs.hash }}.hmpps.service.justice.gov.uk/g;s/$ENV/prod/g' templates/certificate.yml >> 'cloud-platform-environments-prod/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-prod/05-certificates.yml'
- name: Create dev pull request
id: dev-pr
uses: ./.github/actions/create-signed-pull-request
with:
path: cloud-platform-environments-dev
add-paths: namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-dev
branch: ${{ inputs.issue_number }}-create-${{ inputs.project_name }}-infra-dev
commit-message: ${{ inputs.issue_number }} Create certificate for ${{ inputs.project_name }} (dev)
private-key: ${{ secrets.BOT_GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.BOT_GPG_PASSPHRASE }}
token: ${{ secrets.BOT_GITHUB_EXTERNAL_REPOS_TOKEN }}
- name: Create preprod pull request
id: preprod-pr
uses: ./.github/actions/create-signed-pull-request
with:
path: cloud-platform-environments-preprod
add-paths: namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-preprod
branch: ${{ inputs.issue_number }}-create-${{ inputs.project_name }}-infra-preprod
commit-message: ${{ inputs.issue_number }} Create certificate for ${{ inputs.project_name }} (preprod)
private-key: ${{ secrets.BOT_GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.BOT_GPG_PASSPHRASE }}
token: ${{ secrets.BOT_GITHUB_EXTERNAL_REPOS_TOKEN }}
- name: Create prod pull request
id: prod-pr
uses: ./.github/actions/create-signed-pull-request
with:
path: cloud-platform-environments-prod
add-paths: namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-probation-integration-services-prod
branch: ${{ inputs.issue_number }}-create-${{ inputs.project_name }}-infra-prod
commit-message: ${{ inputs.issue_number }} Create Pingdom check and certificate for ${{ inputs.project_name }} (prod)
private-key: ${{ secrets.BOT_GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.BOT_GPG_PASSPHRASE }}
token: ${{ secrets.BOT_GITHUB_EXTERNAL_REPOS_TOKEN }}
- name: Create issue for manual steps
run: |
gh issue create \
--title '${{ inputs.issue_number }} Complete infrastructure setup for ${{ inputs.project_name }}' \
--body '
- [ ] Request approval in [#ask-cloud-platform](https://mojdt.slack.com/archives/C57UPMZLY) for the following pull requests
> ${{ steps.dev-pr.outputs.pull-request-url }}
> ${{ steps.preprod-pr.outputs.pull-request-url }}
> ${{ steps.prod-pr.outputs.pull-request-url }}
- [ ] Merge the pull requests' \
--label bootstrap
env:
GITHUB_TOKEN: ${{ github.token }}