Merge pull request #3201 from grafana/dev

Dev to main
This commit is contained in:
Michael Derynck 2023-10-25 14:19:33 -06:00 committed by GitHub
commit e5e27e2bbe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 292 additions and 40 deletions

View file

@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## v1.3.47 (2023-10-25)
### Fixed
- Add filtering term length check for channel filter endpoints @Ferril ([#3192](https://github.com/grafana/oncall/pull/3192))
## v1.3.46 (2023-10-23)
### Added

View file

@ -275,7 +275,7 @@ PATHS_mimir='docs/sources/mimir'
PATHS_plugins_grafana_jira_datasource='docs/sources'
PATHS_plugins_grafana_mongodb_datasource='docs/sources'
PATHS_plugins_grafana_splunk_datasource='docs/sources'
Paths_tempo='docs/sources/tempo'
PATHS_tempo='docs/sources/tempo'
PATHS_website='content'
# identifier STR

View file

@ -213,21 +213,22 @@ Grafana OnCall supports Twilio SMS and phone call notifications delivery. If you
notifications using Twilio, complete the following steps:
1. Set `GRAFANA_CLOUD_NOTIFICATIONS_ENABLED` as **False** to ensure the Grafana OSS <-> Cloud connector is disabled.
1. From your **OnCall** environment, select **Env Variables** and configure all variables starting with `TWILIO_`.
2. From your **OnCall** environment, select **Env Variables** and configure all variables starting with `TWILIO_`.
### Zvonok.com
Grafana OnCall supports Zvonok.com phone call notifications delivery. To configure phone call notifications using
Zvonok.com, complete the following steps:
1. Change `PHONE_PROVIDER` value to `zvonok`.
2. Create a public API key on the Profile->Settings page, and assign its value to `ZVONOK_API_KEY`.
3. Create campaign and assign its ID value to `ZVONOK_CAMPAIGN_ID`.
4. If you are planning to use pre-recorded audio instead of a speech synthesizer, you can copy the ID of the audio clip
1. Set `GRAFANA_CLOUD_NOTIFICATIONS_ENABLED` as **False** to ensure the Grafana OSS <-> Cloud connector is disabled.
2. Change `PHONE_PROVIDER` value to `zvonok`.
3. Create a public API key on the Profile->Settings page, and assign its value to `ZVONOK_API_KEY`.
4. Create campaign and assign its ID value to `ZVONOK_CAMPAIGN_ID`.
5. If you are planning to use pre-recorded audio instead of a speech synthesizer, you can copy the ID of the audio clip
to the variable `ZVONOK_AUDIO_ID` (optional step).
5. To make a call with a specific voice, you can set the `ZVONOK_SPEAKER_ID`.
6. To make a call with a specific voice, you can set the `ZVONOK_SPEAKER_ID`.
By default, the ID used is `Salli` (optional step).
6. To process the call status, it is required to add a postback with the GET/POST method on the side of the zvonok.com
7. To process the call status, it is required to add a postback with the GET/POST method on the side of the zvonok.com
service with the following format (optional step):
`${ONCALL_BASE_URL}/zvonok/call_status_events?campaign_id={ct_campaign_id}&call_id={ct_call_id}&status={ct_status}&user_choice={ct_user_choice}`

View file

@ -437,6 +437,8 @@ class AlertGroupSlackRenderer(AlertGroupBaseRenderer):
data = {
"organization_id": self.alert_group.channel.organization_id,
"alert_group_pk": self.alert_group.pk,
# eventually replace using alert_group_pk with alert_group_public_pk in slack payload
"alert_group_ppk": self.alert_group.public_primary_key,
**kwargs,
}
return json.dumps(data) # Slack block elements allow to pass value as string only (max 2000 chars)

View file

@ -76,7 +76,9 @@ class ChannelFilter(OrderedModel):
notification_backends = models.JSONField(null=True, default=None)
created_at = models.DateTimeField(auto_now_add=True)
filtering_term = models.CharField(max_length=1024, null=True, default=None)
FILTERING_TERM_MAX_LENGTH = 1024
filtering_term = models.CharField(max_length=FILTERING_TERM_MAX_LENGTH, null=True, default=None)
FILTERING_TERM_TYPE_REGEX = 0
FILTERING_TERM_TYPE_JINJA2 = 1

View file

@ -60,6 +60,12 @@ class ChannelFilterSerializer(EagerLoadingMixin, serializers.ModelSerializer):
def validate(self, data):
filtering_term = data.get("filtering_term")
filtering_term_type = data.get("filtering_term_type")
if filtering_term is not None:
if len(filtering_term) > ChannelFilter.FILTERING_TERM_MAX_LENGTH:
raise serializers.ValidationError(
f"Expression is too long. Maximum length: {ChannelFilter.FILTERING_TERM_MAX_LENGTH} characters, "
f"current length: {len(filtering_term)}"
)
if filtering_term_type == ChannelFilter.FILTERING_TERM_TYPE_JINJA2:
try:
valid_jinja_template_for_serializer_method_field({"route_template": filtering_term})
@ -141,7 +147,6 @@ class ChannelFilterSerializer(EagerLoadingMixin, serializers.ModelSerializer):
class ChannelFilterCreateSerializer(ChannelFilterSerializer):
alert_receive_channel = OrganizationFilteredPrimaryKeyRelatedField(queryset=AlertReceiveChannel.objects)
slack_channel = serializers.CharField(allow_null=True, required=False, source="slack_channel_id")
filtering_term = serializers.CharField(required=False, allow_null=True, allow_blank=True)
class Meta:
model = ChannelFilter

View file

@ -552,3 +552,41 @@ def test_channel_filter_convert_from_regex_to_jinja2(
assert jinja2_channel_filter.filtering_term == final_filtering_term
# Check if the same alert is matched to the channel filter (route) new jinja2
assert bool(jinja2_channel_filter.is_satisfying(payload)) is True
@pytest.mark.django_db
def test_channel_filter_long_filtering_term(
make_organization_and_user_with_plugin_token,
make_alert_receive_channel,
make_escalation_chain,
make_channel_filter,
make_user_auth_headers,
):
organization, user, token = make_organization_and_user_with_plugin_token()
alert_receive_channel = make_alert_receive_channel(organization)
make_escalation_chain(organization)
make_channel_filter(alert_receive_channel, is_default=True)
client = APIClient()
long_filtering_term = "a" * (ChannelFilter.FILTERING_TERM_MAX_LENGTH + 1)
url = reverse("api-internal:channel_filter-list")
data_for_creation = {
"alert_receive_channel": alert_receive_channel.public_primary_key,
"filtering_term": long_filtering_term,
}
response = client.post(url, data=data_for_creation, format="json", **make_user_auth_headers(user, token))
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert "Expression is too long" in response.json()["non_field_errors"][0]
channel_filter = make_channel_filter(alert_receive_channel, filtering_term="a", is_default=False)
url = reverse("api-internal:channel_filter-detail", kwargs={"pk": channel_filter.public_primary_key})
data_for_update = {
"filtering_term": long_filtering_term,
}
response = client.put(url, data=data_for_update, format="json", **make_user_auth_headers(user, token))
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert "Expression is too long" in response.json()["non_field_errors"][0]

View file

@ -163,8 +163,14 @@ class ChannelFilterSerializer(BaseChannelFilterSerializer):
return super().create(validated_data)
def validate(self, data):
filtering_term = data.get("routing_regex")
filtering_term_type = data.get("routing_type")
filtering_term = data.get("filtering_term")
filtering_term_type = data.get("filtering_term_type")
if filtering_term is not None:
if len(filtering_term) > ChannelFilter.FILTERING_TERM_MAX_LENGTH:
raise serializers.ValidationError(
f"Expression is too long. Maximum length: {ChannelFilter.FILTERING_TERM_MAX_LENGTH} characters, "
f"current length: {len(filtering_term)}"
)
if filtering_term_type == ChannelFilter.FILTERING_TERM_TYPE_JINJA2:
try:
valid_jinja_template_for_serializer_method_field({"route_template": filtering_term})

View file

@ -455,3 +455,36 @@ def test_update_route_with_manual_ordering(
response = client.put(url, format="json", HTTP_AUTHORIZATION=token, data=data_to_update)
assert response.status_code == status.HTTP_400_BAD_REQUEST
@pytest.mark.django_db
def test_routes_long_filtering_term(
route_public_api_setup,
make_channel_filter,
):
organization, _, token, alert_receive_channel, escalation_chain, _ = route_public_api_setup
client = APIClient()
long_filtering_term = "a" * (ChannelFilter.FILTERING_TERM_MAX_LENGTH + 1)
url = reverse("api-public:routes-list")
data_for_creation = {
"integration_id": alert_receive_channel.public_primary_key,
"escalation_chain_id": escalation_chain.public_primary_key,
"routing_regex": long_filtering_term,
}
response = client.post(url, data=data_for_creation, format="json", HTTP_AUTHORIZATION=token)
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert "Expression is too long" in response.json()["non_field_errors"][0]
channel_filter = make_channel_filter(alert_receive_channel, filtering_term="a", is_default=False)
url = reverse("api-public:routes-detail", kwargs={"pk": channel_filter.public_primary_key})
data_for_update = {
"routing_regex": long_filtering_term,
}
response = client.put(url, data=data_for_update, format="json", HTTP_AUTHORIZATION=token)
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert "Expression is too long" in response.json()["non_field_errors"][0]

View file

@ -98,12 +98,27 @@ class AlertGroupActionsMixin:
except (TypeError, json.JSONDecodeError):
return None
# New slack messages from OnCall contain alert group primary key
try:
alert_group_ppk = value["alert_group_ppk"]
return AlertGroup.objects.get(public_primary_key=alert_group_ppk)
except (KeyError, TypeError):
pass
try:
alert_group_pk = value["alert_group_pk"]
organization_pk = value["organization_id"]
except (KeyError, TypeError):
return None
return AlertGroup.objects.get(pk=alert_group_pk)
try:
# check organization as well for cases when the organization was migrated from "us" cluster to "eu" and
# slack message has an outdated payload with incorrect alert group id
alert_group = AlertGroup.objects.get(pk=alert_group_pk, channel__organization_id=organization_pk)
except AlertGroup.DoesNotExist:
return None
return alert_group
def _get_alert_group_from_message(self, payload: EventPayload) -> AlertGroup | None:
"""
@ -128,12 +143,27 @@ class AlertGroupActionsMixin:
except (TypeError, json.JSONDecodeError):
continue
# New slack messages from OnCall contain alert group primary key
try:
alert_group_ppk = value["alert_group_ppk"]
return AlertGroup.objects.get(public_primary_key=alert_group_ppk)
except (KeyError, TypeError):
pass
try:
alert_group_pk = value["alert_group_pk"]
organization_pk = value["organization_id"]
except (KeyError, TypeError):
continue
return AlertGroup.objects.get(pk=alert_group_pk)
try:
# check the organization as well for cases organization was migrated from "us" cluster to "eu" and
# the slack message has an outdated payload with incorrect alert group id
alert_group = AlertGroup.objects.get(pk=alert_group_pk, channel__organization_id=organization_pk)
except AlertGroup.DoesNotExist:
return None
return alert_group
return None
def _get_alert_group_from_slack_message_in_db(

View file

@ -191,7 +191,21 @@ def test_get_alert_group_from_message(
],
"message": {
"ts": "RANDOM_MESSAGE_TS",
"attachments": [{"blocks": [{"elements": [{"value": json.dumps({"alert_group_pk": alert_group.pk})}]}]}],
"attachments": [
{
"blocks": [
{
"elements": [
{
"value": json.dumps(
{"alert_group_pk": alert_group.pk, "organization_id": organization.pk}
)
}
]
}
]
}
],
},
"channel": {"id": "RANDOM_CHANNEL_ID"},
}

View file

@ -81,18 +81,16 @@ def manage_responders_setup(
@pytest.mark.django_db
def test_initial_state(manage_responders_setup):
organization, user, slack_team_identity, slack_user_identity = manage_responders_setup
payload = {
"trigger_id": TRIGGER_ID,
"actions": [
{
"type": "button",
"value": json.dumps({"organization_id": ORGANIZATION_ID, "alert_group_pk": ALERT_GROUP_ID}),
"value": json.dumps({"organization_id": organization.pk, "alert_group_pk": ALERT_GROUP_ID}),
}
],
}
organization, user, slack_team_identity, slack_user_identity = manage_responders_setup
step = StartManageResponders(slack_team_identity, organization, user)
with patch.object(step._slack_client, "views_open") as mock_slack_api_call:
step.process_scenario(slack_user_identity, slack_team_identity, payload)

View file

@ -17,7 +17,11 @@ def test_slack_renderer_acknowledge_button(make_organization, make_alert_receive
button = elements[0]
assert button["text"]["text"] == "Acknowledge"
assert json.loads(button["value"]) == {"organization_id": organization.pk, "alert_group_pk": alert_group.pk}
assert json.loads(button["value"]) == {
"organization_id": organization.pk,
"alert_group_pk": alert_group.pk,
"alert_group_ppk": alert_group.public_primary_key,
}
@pytest.mark.django_db
@ -33,7 +37,11 @@ def test_slack_renderer_unacknowledge_button(
button = elements[0]
assert button["text"]["text"] == "Unacknowledge"
assert json.loads(button["value"]) == {"organization_id": organization.pk, "alert_group_pk": alert_group.pk}
assert json.loads(button["value"]) == {
"organization_id": organization.pk,
"alert_group_pk": alert_group.pk,
"alert_group_ppk": alert_group.public_primary_key,
}
@pytest.mark.django_db
@ -47,7 +55,11 @@ def test_slack_renderer_resolve_button(make_organization, make_alert_receive_cha
button = elements[1]
assert button["text"]["text"] == "Resolve"
assert json.loads(button["value"]) == {"organization_id": organization.pk, "alert_group_pk": alert_group.pk}
assert json.loads(button["value"]) == {
"organization_id": organization.pk,
"alert_group_pk": alert_group.pk,
"alert_group_ppk": alert_group.public_primary_key,
}
@pytest.mark.django_db
@ -61,7 +73,11 @@ def test_slack_renderer_unresolve_button(make_organization, make_alert_receive_c
button = elements[0]
assert button["text"]["text"] == "Unresolve"
assert json.loads(button["value"]) == {"organization_id": organization.pk, "alert_group_pk": alert_group.pk}
assert json.loads(button["value"]) == {
"organization_id": organization.pk,
"alert_group_pk": alert_group.pk,
"alert_group_ppk": alert_group.public_primary_key,
}
@pytest.mark.django_db
@ -96,6 +112,7 @@ def test_slack_renderer_stop_invite_button(
assert json.loads(action["value"]) == {
"organization_id": organization.pk,
"alert_group_pk": alert_group.pk,
"alert_group_ppk": alert_group.public_primary_key,
"invitation_id": invitation.pk,
}
@ -114,7 +131,12 @@ def test_slack_renderer_silence_button(make_organization, make_alert_receive_cha
values = [json.loads(option["value"]) for option in button["options"]]
assert values == [
{"organization_id": organization.pk, "alert_group_pk": alert_group.pk, "delay": delay}
{
"organization_id": organization.pk,
"alert_group_pk": alert_group.pk,
"alert_group_ppk": alert_group.public_primary_key,
"delay": delay,
}
for delay, _ in AlertGroup.SILENCE_DELAY_OPTIONS
]
@ -133,6 +155,7 @@ def test_slack_renderer_unsilence_button(make_organization, make_alert_receive_c
assert json.loads(button["value"]) == {
"organization_id": organization.pk,
"alert_group_pk": alert_group.pk,
"alert_group_ppk": alert_group.public_primary_key,
}
@ -150,6 +173,7 @@ def test_slack_renderer_attach_button(make_organization, make_alert_receive_chan
assert json.loads(button["value"]) == {
"organization_id": organization.pk,
"alert_group_pk": alert_group.pk,
"alert_group_ppk": alert_group.public_primary_key,
}
@ -170,6 +194,7 @@ def test_slack_renderer_unattach_button(make_organization, make_alert_receive_ch
assert json.loads(action["value"]) == {
"organization_id": organization.pk,
"alert_group_pk": alert_group.pk,
"alert_group_ppk": alert_group.public_primary_key,
}
@ -186,7 +211,11 @@ def test_slack_renderer_format_alert_button(
button = elements[5]
assert button["text"]["text"] == ":mag: Format Alert"
assert json.loads(button["value"]) == {"organization_id": organization.pk, "alert_group_pk": alert_group.pk}
assert json.loads(button["value"]) == {
"organization_id": organization.pk,
"alert_group_pk": alert_group.pk,
"alert_group_ppk": alert_group.public_primary_key,
}
@pytest.mark.django_db
@ -205,5 +234,6 @@ def test_slack_renderer_resolution_notes_button(
assert json.loads(button["value"]) == {
"organization_id": organization.pk,
"alert_group_pk": alert_group.pk,
"alert_group_ppk": alert_group.public_primary_key,
"resolution_note_window_action": "edit",
}

View file

@ -53,7 +53,7 @@ django-anymail==8.6
django-deprecate-fields==0.1.1
pymdown-extensions==10.0
requests==2.31.0
urllib3==1.26.17
urllib3==1.26.18
prometheus_client==0.16.0
lxml==4.9.2
babel==2.12.1

View file

@ -22,6 +22,14 @@
dependencies:
"@babel/highlight" "^7.18.6"
"@babel/code-frame@^7.22.13":
version "7.22.13"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
dependencies:
"@babel/highlight" "^7.22.13"
chalk "^2.4.2"
"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.18.8", "@babel/compat-data@^7.20.0", "@babel/compat-data@^7.20.1":
version "7.20.1"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.1.tgz#f2e6ef7790d8c8dbf03d379502dcc246dcce0b30"
@ -69,7 +77,7 @@
json5 "^2.2.1"
semver "^6.3.0"
"@babel/generator@^7.18.9", "@babel/generator@^7.20.1", "@babel/generator@^7.20.2", "@babel/generator@^7.7.2":
"@babel/generator@^7.18.9", "@babel/generator@^7.20.2", "@babel/generator@^7.7.2":
version "7.20.4"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.4.tgz#4d9f8f0c30be75fd90a0562099a26e5839602ab8"
integrity sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==
@ -78,6 +86,16 @@
"@jridgewell/gen-mapping" "^0.3.2"
jsesc "^2.5.1"
"@babel/generator@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420"
integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
dependencies:
"@babel/types" "^7.23.0"
"@jridgewell/gen-mapping" "^0.3.2"
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
"@babel/helper-annotate-as-pure@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb"
@ -141,6 +159,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
"@babel/helper-environment-visitor@^7.22.20":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
"@babel/helper-explode-assignable-expression@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096"
@ -156,6 +179,14 @@
"@babel/template" "^7.18.10"
"@babel/types" "^7.19.0"
"@babel/helper-function-name@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
dependencies:
"@babel/template" "^7.22.15"
"@babel/types" "^7.23.0"
"@babel/helper-hoist-variables@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
@ -163,6 +194,13 @@
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-hoist-variables@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
dependencies:
"@babel/types" "^7.22.5"
"@babel/helper-member-expression-to-functions@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815"
@ -245,16 +283,33 @@
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-split-export-declaration@^7.22.6":
version "7.22.6"
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
dependencies:
"@babel/types" "^7.22.5"
"@babel/helper-string-parser@^7.19.4":
version "7.19.4"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
"@babel/helper-string-parser@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
version "7.19.1"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
"@babel/helper-validator-identifier@^7.22.20":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
"@babel/helper-validator-option@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8"
@ -288,11 +343,25 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.18.9", "@babel/parser@^7.20.1", "@babel/parser@^7.20.2":
"@babel/highlight@^7.22.13":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54"
integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
dependencies:
"@babel/helper-validator-identifier" "^7.22.20"
chalk "^2.4.2"
js-tokens "^4.0.0"
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.18.9", "@babel/parser@^7.20.2":
version "7.20.3"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.3.tgz#5358cf62e380cf69efcb87a7bb922ff88bfac6e2"
integrity sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==
"@babel/parser@^7.22.15", "@babel/parser@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2"
@ -1178,19 +1247,28 @@
"@babel/parser" "^7.18.10"
"@babel/types" "^7.18.10"
"@babel/traverse@^7.18.9", "@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.1", "@babel/traverse@^7.7.2":
version "7.20.1"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.1.tgz#9b15ccbf882f6d107eeeecf263fbcdd208777ec8"
integrity sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==
"@babel/template@^7.22.15":
version "7.22.15"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
dependencies:
"@babel/code-frame" "^7.18.6"
"@babel/generator" "^7.20.1"
"@babel/helper-environment-visitor" "^7.18.9"
"@babel/helper-function-name" "^7.19.0"
"@babel/helper-hoist-variables" "^7.18.6"
"@babel/helper-split-export-declaration" "^7.18.6"
"@babel/parser" "^7.20.1"
"@babel/types" "^7.20.0"
"@babel/code-frame" "^7.22.13"
"@babel/parser" "^7.22.15"
"@babel/types" "^7.22.15"
"@babel/traverse@^7.18.9", "@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.1", "@babel/traverse@^7.7.2":
version "7.23.2"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
dependencies:
"@babel/code-frame" "^7.22.13"
"@babel/generator" "^7.23.0"
"@babel/helper-environment-visitor" "^7.22.20"
"@babel/helper-function-name" "^7.23.0"
"@babel/helper-hoist-variables" "^7.22.5"
"@babel/helper-split-export-declaration" "^7.22.6"
"@babel/parser" "^7.23.0"
"@babel/types" "^7.23.0"
debug "^4.1.0"
globals "^11.1.0"
@ -1203,6 +1281,15 @@
"@babel/helper-validator-identifier" "^7.19.1"
to-fast-properties "^2.0.0"
"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
dependencies:
"@babel/helper-string-parser" "^7.22.5"
"@babel/helper-validator-identifier" "^7.22.20"
to-fast-properties "^2.0.0"
"@bcoe/v8-coverage@^0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"