mirror of https://github.com/grafana/grafana
commit
44a134f72b
@ -1,39 +1,26 @@ |
||||
name: Auto-milestone |
||||
on: |
||||
pull_request: |
||||
pull_request_target: |
||||
types: |
||||
- opened |
||||
- reopened |
||||
- closed |
||||
- ready_for_review |
||||
|
||||
jobs: |
||||
config: |
||||
runs-on: "ubuntu-latest" |
||||
outputs: |
||||
has-secrets: ${{ steps.check.outputs.has-secrets }} |
||||
steps: |
||||
- name: "Check for secrets" |
||||
id: check |
||||
shell: bash |
||||
run: | |
||||
if [ -n "${{ (secrets.GRAFANA_DELIVERY_BOT_APP_ID != '' && secrets.GRAFANA_DELIVERY_BOT_APP_PEM != '') || '' }}" ]; then |
||||
echo "has-secrets=1" >> "$GITHUB_OUTPUT" |
||||
fi |
||||
permissions: |
||||
pull-requests: write |
||||
|
||||
# Note: this action runs with write permissions on GITHUB_TOKEN even from forks |
||||
# so it must not run untrusted code (such as checking out the pull request) |
||||
jobs: |
||||
main: |
||||
needs: config |
||||
if: needs.config.outputs.has-secrets |
||||
runs-on: ubuntu-latest |
||||
if: github.event.pull_request.draft == false |
||||
steps: |
||||
- name: "Generate token" |
||||
id: generate_token |
||||
uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 |
||||
with: |
||||
app_id: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_ID }} |
||||
private_key: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_PEM }} |
||||
|
||||
# Note: Github will not trigger other actions from this because it uses |
||||
# the GITHUB_TOKEN token |
||||
- name: Run auto-milestone |
||||
uses: grafana/grafana-github-actions-go/auto-milestone@main |
||||
with: |
||||
pr: ${{ github.event.pull_request.number }} |
||||
token: ${{ steps.generate_token.outputs.token }} |
||||
token: ${{ secrets.GITHUB_TOKEN }} |
||||
|
@ -0,0 +1,16 @@ |
||||
route: |
||||
group_by: ['alertname'] |
||||
group_wait: 30s |
||||
group_interval: 5m |
||||
repeat_interval: 1h |
||||
receiver: 'web.hook' |
||||
receivers: |
||||
- name: 'web.hook' |
||||
webhook_configs: |
||||
- url: 'http://127.0.0.1:5001/' |
||||
inhibit_rules: |
||||
- source_match: |
||||
severity: 'critical' |
||||
target_match: |
||||
severity: 'warning' |
||||
equal: ['alertname', 'dev', 'instance'] |
@ -0,0 +1,39 @@ |
||||
import * as e2e from '@grafana/e2e-selectors'; |
||||
import { expect, test } from '@grafana/plugin-e2e'; |
||||
|
||||
test('should evaluate to false if entire request returns 500', async ({ page, alertRuleEditPage, selectors }) => { |
||||
await alertRuleEditPage.alertRuleNameField.fill('Test Alert Rule'); |
||||
|
||||
// remove the default query
|
||||
const queryA = alertRuleEditPage.getAlertRuleQueryRow('A'); |
||||
await alertRuleEditPage |
||||
.getByGrafanaSelector(selectors.components.QueryEditorRow.actionButton('Remove query'), { |
||||
root: queryA.locator, |
||||
}) |
||||
.click(); |
||||
await expect(alertRuleEditPage.evaluate()).not.toBeOK(); |
||||
}); |
||||
|
||||
test('should evaluate to false if entire request returns 200 but partial query result is invalid', async ({ |
||||
page, |
||||
alertRuleEditPage, |
||||
}) => { |
||||
await alertRuleEditPage.alertRuleNameField.fill('Test Alert Rule'); |
||||
|
||||
//add working query
|
||||
const queryA = alertRuleEditPage.getAlertRuleQueryRow('A'); |
||||
await queryA.datasource.set('gdev-prometheus'); |
||||
await queryA.locator.getByLabel('Code').click(); |
||||
await page.waitForFunction(() => window.monaco); |
||||
await queryA.getByGrafanaSelector(e2e.selectors.components.QueryField.container).click(); |
||||
await page.keyboard.insertText('topk(5, max(scrape_duration_seconds) by (job))'); |
||||
|
||||
//add broken query
|
||||
const newQuery = await alertRuleEditPage.clickAddQueryRow(); |
||||
await newQuery.datasource.set('gdev-prometheus'); |
||||
await newQuery.locator.getByLabel('Code').click(); |
||||
await newQuery.getByGrafanaSelector(e2e.selectors.components.QueryField.container).click(); |
||||
await page.keyboard.insertText('topk(5,'); |
||||
|
||||
await expect(alertRuleEditPage.evaluate()).not.toBeOK(); |
||||
}); |
@ -1,7 +1,7 @@ |
||||
import testDashboard from '../dashboards/TestDashboard.json'; |
||||
import { e2e } from '../utils'; |
||||
|
||||
describe('Dashboard browse', () => { |
||||
// Skipping due to race conditions with same old arch test e2e/dashboards-suite/dashboard-browse.spec.ts
|
||||
describe.skip('Dashboard browse', () => { |
||||
beforeEach(() => { |
||||
e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); |
||||
}); |
@ -1,6 +1,6 @@ |
||||
import React, { useEffect, useState } from 'react'; |
||||
|
||||
import { store } from '../store'; |
||||
import { store } from './store'; |
||||
|
||||
export interface Props<T> { |
||||
storageKey: string; |
@ -1,6 +0,0 @@ |
||||
// reset font file paths so storybook loads them based on |
||||
// staticDirs defined in packages/grafana-ui/.storybook/main.ts |
||||
$font-file-path: './public/fonts'; |
||||
$fa-font-path: $font-file-path; |
||||
|
||||
@import '../../../public/sass/grafana.dark.scss'; |
@ -1,6 +0,0 @@ |
||||
// reset font file paths so storybook loads them based on |
||||
// staticDirs defined in packages/grafana-ui/.storybook/main.ts |
||||
$font-file-path: './public/fonts'; |
||||
$fa-font-path: $font-file-path; |
||||
|
||||
@import '../../../public/sass/grafana.light.scss'; |
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,54 @@ |
||||
package util |
||||
|
||||
import ( |
||||
"fmt" |
||||
"net/url" |
||||
"strings" |
||||
) |
||||
|
||||
const masking = "hidden" |
||||
|
||||
var sensitiveQueryChecks = map[string]func(key string, urlValues url.Values) bool{ |
||||
"auth_token": func(key string, urlValues url.Values) bool { |
||||
return true |
||||
}, |
||||
"x-amz-signature": func(key string, urlValues url.Values) bool { |
||||
return true |
||||
}, |
||||
"x-goog-signature": func(key string, urlValues url.Values) bool { |
||||
return true |
||||
}, |
||||
"sig": func(key string, urlValues url.Values) bool { |
||||
for k := range urlValues { |
||||
if strings.ToLower(k) == "sv" { |
||||
return true |
||||
} |
||||
} |
||||
return false |
||||
}, |
||||
} |
||||
|
||||
func SanitizeURI(s string) (string, error) { |
||||
if s == "" { |
||||
return s, nil |
||||
} |
||||
|
||||
u, err := url.ParseRequestURI(s) |
||||
if err != nil { |
||||
return "", fmt.Errorf("failed to sanitize URL") |
||||
} |
||||
|
||||
// strip out sensitive query strings
|
||||
urlValues := u.Query() |
||||
for key := range urlValues { |
||||
lk := strings.ToLower(key) |
||||
if checker, ok := sensitiveQueryChecks[lk]; ok { |
||||
if checker(key, urlValues) { |
||||
urlValues.Set(key, masking) |
||||
} |
||||
} |
||||
} |
||||
u.RawQuery = urlValues.Encode() |
||||
|
||||
return u.String(), nil |
||||
} |
@ -0,0 +1,74 @@ |
||||
package util |
||||
|
||||
import ( |
||||
"testing" |
||||
|
||||
"github.com/stretchr/testify/assert" |
||||
) |
||||
|
||||
func Test_sanitizeURI(t *testing.T) { |
||||
tests := []struct { |
||||
name string |
||||
input string |
||||
want string |
||||
expectError bool |
||||
}{ |
||||
{ |
||||
name: "Receiving empty string should return it", |
||||
input: "", |
||||
want: "", |
||||
}, |
||||
{ |
||||
name: "Receiving URL with auth_token should remove it", |
||||
input: "https://grafana.com/?auth_token=secret-token&q=1234", |
||||
want: "https://grafana.com/?auth_token=hidden&q=1234", |
||||
}, |
||||
{ |
||||
name: "Receiving presigned URL from AWS should remove signature", |
||||
input: "https://s3.amazonaws.com/finance-department-bucket/2022/tax-certificate.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA3SGQVQG7FGA6KKA6%2F20221104%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20221104T140227Z&X-Amz-Expires=3600&X-Amz-Signature=b22&X-Amz-SignedHeaders=host", |
||||
want: "https://s3.amazonaws.com/finance-department-bucket/2022/tax-certificate.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA3SGQVQG7FGA6KKA6%2F20221104%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20221104T140227Z&X-Amz-Expires=3600&X-Amz-Signature=hidden&X-Amz-SignedHeaders=host", |
||||
}, |
||||
{ |
||||
name: "Receiving presigned URL from GCP should remove signature", |
||||
input: "https://storage.googleapis.com/example-bucket/cat.jpeg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=example%40example-project.iam.gserviceaccount.com%2F20181026%2Fus-central1%2Fstorage%2Fgoog4_request&X-Goog-Date=20181026T181309Z&X-Goog-Expires=900&X-Goog-Signature=247a&X-Goog-SignedHeaders=host", |
||||
want: "https://storage.googleapis.com/example-bucket/cat.jpeg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=example%40example-project.iam.gserviceaccount.com%2F20181026%2Fus-central1%2Fstorage%2Fgoog4_request&X-Goog-Date=20181026T181309Z&X-Goog-Expires=900&X-Goog-Signature=hidden&X-Goog-SignedHeaders=host", |
||||
}, |
||||
{ |
||||
name: "Receiving presigned URL with lower case query params from GCP should remove signature", |
||||
input: "https://storage.googleapis.com/example-bucket/cat.jpeg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=example%40example-project.iam.gserviceaccount.com%2F20181026%2Fus-central1%2Fstorage%2Fgoog4_request&X-Goog-Date=20181026T181309Z&X-Goog-Expires=900&x-goog-signature=247a&X-Goog-SignedHeaders=host", |
||||
want: "https://storage.googleapis.com/example-bucket/cat.jpeg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=example%40example-project.iam.gserviceaccount.com%2F20181026%2Fus-central1%2Fstorage%2Fgoog4_request&X-Goog-Date=20181026T181309Z&X-Goog-Expires=900&X-Goog-SignedHeaders=host&x-goog-signature=hidden", |
||||
}, |
||||
{ |
||||
name: "Receiving presigned URL from Azure should remove signature", |
||||
input: "https://myaccount.queue.core.windows.net/myqueue/messages?se=2015-07-02T08%3A49Z&si=YWJjZGVmZw%3D%3D&sig=jDrr6cna7JPwIaxWfdH0tT5v9dc%3d&sp=p&st=2015-07-01T08%3A49Z&sv=2015-02-21&visibilitytimeout=120", |
||||
want: "https://myaccount.queue.core.windows.net/myqueue/messages?se=2015-07-02T08%3A49Z&si=YWJjZGVmZw%3D%3D&sig=hidden&sp=p&st=2015-07-01T08%3A49Z&sv=2015-02-21&visibilitytimeout=120", |
||||
}, |
||||
{ |
||||
name: "Receiving presigned URL from Azure with upper case query values should remove signature", |
||||
input: "https://myaccount.queue.core.windows.net/myqueue/messages?se=2015-07-02T08%3A49Z&si=YWJjZGVmZw%3D%3D&SIG=jDrr6cna7JPwIaxWfdH0tT5v9dc%3d&sp=p&st=2015-07-01T08%3A49Z&SV=2015-02-21&visibilitytimeout=120", |
||||
want: "https://myaccount.queue.core.windows.net/myqueue/messages?SIG=hidden&SV=2015-02-21&se=2015-07-02T08%3A49Z&si=YWJjZGVmZw%3D%3D&sp=p&st=2015-07-01T08%3A49Z&visibilitytimeout=120", |
||||
}, |
||||
{ |
||||
name: "Receiving valid URL string should return it parsed", |
||||
input: "https://grafana.com/?sig=testing-a-generic-parameter", |
||||
want: "https://grafana.com/?sig=testing-a-generic-parameter", |
||||
}, |
||||
{ |
||||
name: "Receiving invalid URL string should return empty string", |
||||
input: "this is not a valid URL", |
||||
want: "", |
||||
expectError: true, |
||||
}, |
||||
} |
||||
for _, tt := range tests { |
||||
t.Run(tt.name, func(t *testing.T) { |
||||
url, err := SanitizeURI(tt.input) |
||||
if tt.expectError { |
||||
assert.Error(t, err) |
||||
} else { |
||||
assert.NoError(t, err) |
||||
} |
||||
assert.Equalf(t, tt.want, url, "SanitizeURI(%v)", tt.input) |
||||
}) |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue