Merge branch 'main' into giuseppe/break-sri-checks

This commit is contained in:
Giuseppe Guerra
2024-10-11 10:57:27 +02:00
252 changed files with 5517 additions and 3760 deletions
-4
View File
@@ -6712,10 +6712,6 @@ exports[`better eslint`] = {
"public/app/plugins/panel/timeseries/SpanNullsEditor.tsx:5381": [
[0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"]
],
"public/app/plugins/panel/timeseries/TimezonesEditor.tsx:5381": [
[0, 0, 0, "Styles should be written using objects.", "0"],
[0, 0, 0, "Styles should be written using objects.", "1"]
],
"public/app/plugins/panel/timeseries/migrations.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Do not use any type assertions.", "1"],
-1
View File
@@ -731,7 +731,6 @@ embed.go @grafana/grafana-as-code
/.github/workflows/remove-milestone.yml @grafana/grafana-release-guild
/.github/workflows/sbom-report.yml @grafana/security-team
/.github/workflows/scripts/json-file-to-job-output.js @grafana/plugins-platform-frontend
/.github/workflows/scripts/pr-get-job-link.js @grafana/plugins-platform-frontend
/.github/workflows/stale.yml @grafana/grafana-release-guild
/.github/workflows/update-changelog.yml @grafana/grafana-release-guild
/.github/workflows/update-make-docs.yml @grafana/docs-tooling
-8
View File
@@ -59,14 +59,6 @@
"url": "https://github.com/orgs/grafana/projects/76"
}
},
{
"type": "label",
"name": "type/docs",
"action": "addToProject",
"addToProject": {
"url": "https://github.com/orgs/grafana/projects/69"
}
},
{
"type": "label",
"name": "datasource/Azure",
@@ -6,6 +6,10 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
id-token: write
on:
pull_request:
paths:
@@ -154,26 +158,16 @@ jobs:
project_id: 'grafanalabs-global'
install_components: 'bq'
- name: Get link for the Github Action job
id: job
uses: actions/github-script@v6
with:
script: |
const name = 'Detect breaking changes';
const script = require('./.github/workflows/scripts/pr-get-job-link.js')
await script({name, github, context, core})
- name: Detect breaking changes
id: breaking-changes
run: ./scripts/check-breaking-changes.sh
env:
FORCE_COLOR: 3
GITHUB_JOB_LINK: ${{ steps.job.outputs.link }}
- name: Persisting the check output
run: |
mkdir -p ./levitate
echo "{ \"exit_code\": ${{ steps.breaking-changes.outputs.is_breaking }}, \"message\": \"${{ steps.breaking-changes.outputs.message }}\", \"job_link\": \"${{ steps.job.outputs.link }}#step:${GITHUB_STEP_NUMBER}:1\", \"pr_number\": \"${{ github.event.pull_request.number }}\" }" > ./levitate/result.json
echo "{ \"exit_code\": ${{ steps.breaking-changes.outputs.is_breaking }}, \"message\": \"${{ steps.breaking-changes.outputs.message }}\", \"pr_number\": \"${{ github.event.pull_request.number }}\" }" > ./levitate/result.json
- name: Upload check output as artifact
uses: actions/upload-artifact@v4
@@ -219,15 +213,12 @@ jobs:
PR_NUMBER: ${{ github.event.pull_request.number }}
with:
script: |
const { data } = await github.rest.issues.listLabelsOnIssue({
issue_number: process.env.PR_NUMBER,
const { data: labels } = await github.rest.issues.listLabelsOnIssue({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
});
const labels = data.map(({ name }) => name);
const doesExist = labels.includes('levitate breaking change');
return doesExist ? 1 : 0;
return labels.some(label => label.name === 'levitate breaking change') ? 1 : 0
# put the markdown into a variable
- name: Levitate Markdown
@@ -271,22 +262,41 @@ jobs:
delete: true
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
# Posts a notification to Slack if a PR has a breaking change and it did not have a breaking change before
- name: Post to Slack
- name: Send Slack Message via Payload
id: slack
if: steps.levitate-run.outputs.exit_code == 1 && steps.does-label-exist.outputs.result == 0 && env.HAS_SECRETS
uses: slackapi/slack-github-action@v1.26.0
if: steps.levitate-run.outputs.exit_code == 1 && steps.does-label-exist.outputs.result == 0 && github.repository == 'grafana/grafana'
uses: grafana/shared-workflows/actions/send-slack-message@main
with:
payload: |
channel-id: "C031SLFH6G0"
payload: |
{
"pr_link": "https://github.com/grafana/grafana/pull/${{ steps.levitate-run.outputs.pr_number }}",
"pr_number": "${{ steps.levitate-run.outputs.pr_number }}",
"job_link": "${{ steps.levitate-run.outputs.job_link }}",
"message": "${{ steps.levitate-run.outputs.message }}"
"channel": "C031SLFH6G0",
"text": ":warning: Possible breaking changes detected in *PR:* <${{ github.event.pull_request.html_url }}|#${{ github.event.pull_request.number }} :warning:",
"icon_emoji": ":grot:",
"username": "Levitate Bot",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*grafana/grafana* repository has possible breaking changes"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*PR:* <${{ github.event.pull_request.html_url }}|#${{ github.event.pull_request.number }}>"
},
{
"type": "mrkdwn",
"text": "*Job:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Job>"
}
]
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_LEVITATE_WEBHOOK_URL }}
HAS_SECRETS: ${{ (github.repository == 'grafana/grafana' || secrets.SLACK_LEVITATE_WEBHOOK_URL != '') || '' }}
# Add the label
- name: Add "levitate breaking change" label
@@ -1,9 +0,0 @@
module.exports = async ({ name, github, context, core }) => {
const { owner, repo } = context.repo;
const url = `https://api.github.com/repos/${owner}/${repo}/actions/runs/${context.runId}/jobs`
const result = await github.request(url);
const job = result.data.jobs.find(j => j.name === name);
core.setOutput('link', `${job.html_url}?check_suite_focus=true`);
}
+2 -1
View File
@@ -17,6 +17,7 @@ GO_RACE_FLAG := $(if $(GO_RACE),-race)
GO_BUILD_FLAGS += $(if $(GO_BUILD_DEV),-dev)
GO_BUILD_FLAGS += $(if $(GO_BUILD_TAGS),-build-tags=$(GO_BUILD_TAGS))
GO_BUILD_FLAGS += $(GO_RACE_FLAG)
GIT_BASE = remotes/origin/main
# GNU xargs has flag -r, and BSD xargs (e.g. MacOS) has that behaviour by default
XARGSR = $(shell xargs --version 2>&1 | grep -q GNU && echo xargs -r || echo xargs)
@@ -308,7 +309,7 @@ lint-go: golangci-lint ## Run all code checks for backend. You can use GO_LINT_F
.PHONY: lint-go-diff
lint-go-diff: $(GOLANGCI_LINT)
git diff --name-only remotes/origin/main | \
git diff --name-only $(GIT_BASE) | \
grep '\.go$$' | \
$(XARGSR) dirname | \
sort -u | \
@@ -39,6 +39,11 @@ refs:
destination: /docs/grafana/<GRAFANA_VERSION>/administration/roles-and-permissions/access-control/
- pattern: /docs/grafana-cloud/
destination: /docs/grafana/<GRAFANA_VERSION>/administration/roles-and-permissions/access-control/
permission:
- pattern: /docs/grafana/
destination: /docs/grafana/<GRAFANA_VERSION>/administration/roles-and-permissions/
- pattern: /docs/grafana-cloud/
destination: /docs/grafana/<GRAFANA_VERSION>/administration/roles-and-permissions/
role-based-access-control:
- pattern: /docs/grafana/
destination: /docs/grafana/<GRAFANA_VERSION>/administration/roles-and-permissions/access-control/
@@ -109,7 +114,7 @@ For information about recent improvements to the reporting UI, refer to [Grafana
## Access control
When [RBAC](ref:rbac) is enabled, you need to have the relevant [Permissions][] to create and manage reports.
When [RBAC](ref:rbac) is enabled, you need to have the relevant [Permissions](ref:permission) to create and manage reports.
## Create or update a report
@@ -191,11 +191,10 @@ Experimental features might be changed or removed without prior notice.
| `queryLibrary` | Enables Query Library feature in Explore |
| `logsExploreTableDefaultVisualization` | Sets the logs table as default visualisation in logs explore |
| `alertingListViewV2` | Enables the new alert list view design |
| `dashboardRestore` | Enables deleted dashboard restore feature (backend only) |
| `dashboardRestore` | Enables deleted dashboard restore feature |
| `alertingCentralAlertHistory` | Enables the new central alert history. |
| `failWrongDSUID` | Throws an error if a datasource has an invalid UIDs |
| `alertingApiServer` | Register Alerting APIs with the K8s API server |
| `dashboardRestoreUI` | Enables the frontend to be able to restore a recently deleted dashboard |
| `dataplaneAggregator` | Enable grafana dataplane aggregator |
| `newFiltersUI` | Enables new combobox style UI for the Ad hoc filters variable in scenes architecture |
| `lokiSendDashboardPanelNames` | Send dashboard and panel names to Loki when querying |
@@ -231,21 +231,34 @@ This app registration will be used as a Service Account to retrieve more informa
1. Go to the [Azure portal](https://portal.azure.com/#home) and sign in with your Azure AD account.
1. In the left-hand navigation pane, select the Azure Active Directory service, and then select **App registrations**.
1. Select **New registration**.
1. Click the **New registration** button.
1. In the **Register an application** pane, enter a name for the application.
1. In the **Supported account types** section, select the account types that can use the application.
1. In the **Redirect URI** section, select Web and enter `https://localhost/login/azuread`.
1. Select **Register**.
1. Click the **Register** button.
#### Set up permissions for the application
1. In the overview pane, look for **API permissions** section and select **Add a permission**.
1. In the **Request API permissions** pane, select **Microsoft Graph**, and click **Application permissions**.
1. In the **Select permissions** pane, under the **GroupMember** section, select **GroupMember.Read.All**.
1. In the **Select permissions** pane, under the **User** section, select **User.Read.All**.
1. Click the **Add permissions** button at the bottom of the page.
1. In the **Request API permissions** pane, select **Microsoft Graph**, and click **Delegated permissions**.
1. In the **Select permissions** pane, under the **User** section, select **User.Read**.
1. Select **Add permissions** at the bottom of the page.
1. Click the **Add permissions** button at the bottom of the page.
1. In the **API permissions** section, select **Grant admin consent for <your-organization>**.
The following table shows what the permissions look like from the Azure AD portal:
| Permissions name | Type | Admin consent required | Status |
| ---------------- | ----------- | ---------------------- | ------- |
| `Group.Read.All` | Application | Yes | Granted |
| `User.Read` | Delegated | No | Granted |
| `User.Read.All` | Application | Yes | Granted |
{{< figure src="/media/docs/grafana/saml/graph-api-app-permissions.png" caption="Screen shot of the permissions listed in Azure AD for the App registration" >}}
#### Generate a client secret
1. In the **Overview** pane, select **Certificates & secrets**.
@@ -278,6 +278,67 @@ To install plugins in the Grafana Helm Charts, complete the following steps:
1. Search for the above plugins and they should be marked as installed.
### Configure a Private CA (Certificate Authority)
In many enterprise networks, TLS certificates are issued by a private certificate authority and are not trusted by default (using the provided OS trust chain).
If your Grafana instance needs to interact with services exposing certificates issued by these private CAs, then you need to ensure Grafana trusts the root certificate.
You might need to configure this if you:
- have plugins that require connectivity to other self hosted systems. For example, if you've installed the Grafana Enterprise Metrics, Logs, or Traces (GEM, GEL, GET) plugins, and your GEM (or GEL/GET) cluster is using a private certificate.
- want to connect to data sources which are listening on HTTPS with a private certificate.
- are using a backend database for persistence, or caching service that uses private certificates for encryption in transit.
In some cases you can specify a self-signed certificate within Grafana (such as in some data sources), or choose to skip TLS certificate validation (this is not recommended unless absolutely necessary).
A simple solution which should work across your entire instance (plugins, data sources, and backend connections) is to add your self-signed CA certificate to your Kubernetes deployment.
1. Create a ConfigMap containing the certificate, and deploy it to your Kubernetes cluster
```yaml
# grafana-ca-configmap.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: grafana-ca-cert
data:
ca.pem: |
-----BEGIN CERTIFICATE-----
(rest of the CA cert)
-----END CERTIFICATE-----
```
```bash
kubectl apply --filename grafana-ca-configmap.yaml --namespace monitoring
```
1. Open the Helm `values.yaml` file in your favorite editor.
1. Find the line that says `extraConfigmapMounts:` and under that section, specify the additional ConfigMap that you want to mount.
```yaml
.......
............
......
extraConfigmapMounts:
- name: ca-certs-configmap
mountPath: /etc/ssl/certs/ca.pem
subPath: ca.pem
configMap: grafana-ca-cert
readOnly: true
.......
............
......
```
1. Save the changes and use the `helm upgrade` command to update your Grafana deployment and mount the new ConfigMap:
```bash
helm upgrade my-grafana grafana/grafana --values values.yaml --namespace monitoring
```
## Troubleshooting
This section includes troubleshooting tips you might find helpful when deploying Grafana on Kubernetes via Helm.
+1 -1
View File
@@ -22,7 +22,7 @@ We recommend that you upgrade Grafana often to stay current with the latest fixe
Because Grafana upgrades are backward compatible, the upgrade process is straightforward, and dashboards and graphs will not change.
To learn what's available in a Grafana release, refer to [What's New ]({{< relref "../whatsnew" >}}).
To learn what's available in a Grafana release, refer to [What's New]({{< relref "../whatsnew" >}}).
Refer to any of the following upgrade guides:
@@ -22,7 +22,9 @@ describe('Shared dashboards', () => {
e2e.pages.ShareDashboardDrawer.ShareExternally.container().should('not.exist');
});
it('Create a shared dashboard and check API', () => {
// Skipping due to being a flaky test
// https://drone.grafana.net/grafana/grafana/201217/6/14
it.skip('Create a shared dashboard and check API', () => {
openDashboard();
// Open share externally drawer
@@ -111,7 +113,7 @@ describe('Shared dashboards', () => {
});
});
it('Disable a shared dashboard', () => {
it.skip('Disable a shared dashboard', () => {
openDashboard();
//TODO Failing in CI/CD. Fix it
+33 -34
View File
@@ -27,11 +27,10 @@ require (
github.com/Masterminds/semver v1.5.0 // @grafana/grafana-backend-group
github.com/Masterminds/semver/v3 v3.2.0 // @grafana/grafana-release-guild
github.com/Masterminds/sprig/v3 v3.2.3 // @grafana/grafana-backend-group
github.com/Masterminds/squirrel v1.5.4 // @grafana/identity-access-team
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // @grafana/plugins-platform-backend
github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // @grafana/grafana-backend-group
github.com/alicebob/miniredis/v2 v2.33.0 // @grafana/alerting-backend
github.com/andybalholm/brotli v1.0.6 // @grafana/partner-datasources
github.com/andybalholm/brotli v1.1.0 // @grafana/partner-datasources
github.com/apache/arrow/go/v15 v15.0.2 // @grafana/observability-metrics
github.com/armon/go-radix v1.0.0 // @grafana/grafana-app-platform-squad
github.com/aws/aws-sdk-go v1.55.5 // @grafana/aws-datasources
@@ -73,7 +72,7 @@ require (
github.com/googleapis/gax-go/v2 v2.13.0 // @grafana/grafana-backend-group
github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group
github.com/gorilla/websocket v1.5.0 // @grafana/grafana-app-platform-squad
github.com/grafana/alerting v0.0.0-20240930154843-22cee00b280e // @grafana/alerting-backend
github.com/grafana/alerting v0.0.0-20241010165806-807ddf183724 // @grafana/alerting-backend
github.com/grafana/authlib v0.0.0-20240919120951-58259833c564 // @grafana/identity-access-team
github.com/grafana/authlib/claims v0.0.0-20240827210201-19d5347dd8dd // @grafana/identity-access-team
github.com/grafana/codejen v0.0.3 // @grafana/dataviz-squad
@@ -123,21 +122,20 @@ require (
github.com/mattn/go-isatty v0.0.20 // @grafana/grafana-backend-group
github.com/mattn/go-sqlite3 v1.14.22 // @grafana/grafana-backend-group
github.com/matttproud/golang_protobuf_extensions v1.0.4 // @grafana/alerting-backend
github.com/microsoft/go-mssqldb v1.7.0 // @grafana/grafana-bi-squad
github.com/microsoft/go-mssqldb v1.7.2 // @grafana/grafana-bi-squad
github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c //@grafana/identity-access-team
github.com/mocktools/go-smtp-mock/v2 v2.3.1 // @grafana/grafana-backend-group
github.com/modern-go/reflect2 v1.0.2 // @grafana/alerting-backend
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // @grafana/alerting-backend
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // @grafana/grafana-operator-experience-squad
github.com/oapi-codegen/oapi-codegen/v2 v2.3.0 // @grafana/grafana-as-code
github.com/oklog/ulid/v2 v2.1.0 // @grafana/identity-access-team
github.com/olekukonko/tablewriter v0.0.5 // @grafana/grafana-backend-group
github.com/openfga/api/proto v0.0.0-20240529184453-5b0b4941f3e0 // @grafana/identity-access-team
github.com/openfga/language/pkg/go v0.0.0-20240409225820-a53ea2892d6d // @grafana/identity-access-team
github.com/openfga/openfga v1.5.4 // @grafana/identity-access-team
github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66 // @grafana/identity-access-team
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f // @grafana/identity-access-team
github.com/openfga/openfga v1.6.2 // @grafana/identity-access-team
github.com/patrickmn/go-cache v2.1.0+incompatible // @grafana/alerting-backend
github.com/prometheus/alertmanager v0.27.0 // @grafana/alerting-backend
github.com/prometheus/client_golang v1.20.3 // @grafana/alerting-backend
github.com/prometheus/client_golang v1.20.4 // @grafana/alerting-backend
github.com/prometheus/client_model v0.6.1 // @grafana/grafana-backend-group
github.com/prometheus/common v0.55.0 // @grafana/alerting-backend
github.com/prometheus/prometheus v1.8.2-0.20221021121301-51a44e6657c3 // @grafana/alerting-backend
@@ -158,21 +156,21 @@ require (
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // @grafana/grafana-operator-experience-squad
github.com/yudai/gojsondiff v1.0.0 // @grafana/grafana-backend-group
go.opentelemetry.io/collector/pdata v1.6.0 // @grafana/grafana-backend-group
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // @grafana/plugins-platform-backend
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 // @grafana/plugins-platform-backend
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.55.0 // @grafana/grafana-operator-experience-squad
go.opentelemetry.io/contrib/propagators/jaeger v1.29.0 // @grafana/grafana-backend-group
go.opentelemetry.io/contrib/samplers/jaegerremote v0.23.0 // @grafana/grafana-backend-group
go.opentelemetry.io/otel v1.30.0 // @grafana/grafana-backend-group
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // @grafana/grafana-backend-group
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // @grafana/grafana-backend-group
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // @grafana/grafana-backend-group
go.opentelemetry.io/otel/sdk v1.29.0 // @grafana/grafana-backend-group
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 // @grafana/grafana-backend-group
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 // @grafana/grafana-backend-group
go.opentelemetry.io/otel/sdk v1.30.0 // @grafana/grafana-backend-group
go.opentelemetry.io/otel/trace v1.30.0 // @grafana/grafana-backend-group
go.uber.org/atomic v1.11.0 // @grafana/alerting-backend
go.uber.org/goleak v1.3.0 // @grafana/grafana-search-and-storage
gocloud.dev v0.39.0 // @grafana/grafana-app-platform-squad
golang.org/x/crypto v0.27.0 // @grafana/grafana-backend-group
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // @grafana/alerting-backend
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // @grafana/alerting-backend
golang.org/x/mod v0.20.0 // indirect; @grafana/grafana-backend-group
golang.org/x/net v0.29.0 // @grafana/oss-big-tent @grafana/partner-datasources
golang.org/x/oauth2 v0.23.0 // @grafana/identity-access-team
@@ -180,9 +178,9 @@ require (
golang.org/x/text v0.18.0 // @grafana/grafana-backend-group
golang.org/x/time v0.6.0 // @grafana/grafana-backend-group
golang.org/x/tools v0.24.0 // @grafana/grafana-as-code
gonum.org/v1/gonum v0.14.0 // @grafana/observability-metrics
gonum.org/v1/gonum v0.15.1 // @grafana/observability-metrics
google.golang.org/api v0.191.0 // @grafana/grafana-backend-group
google.golang.org/grpc v1.66.0 // @grafana/plugins-platform-backend
google.golang.org/grpc v1.67.0 // @grafana/plugins-platform-backend
google.golang.org/protobuf v1.34.2 // @grafana/plugins-platform-backend
gopkg.in/ini.v1 v1.67.0 // @grafana/alerting-backend
gopkg.in/mail.v2 v2.3.1 // @grafana/grafana-backend-group
@@ -224,12 +222,13 @@ require (
github.com/FZambia/eagle v0.1.0 // indirect
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/squirrel v1.5.4 // indirect
github.com/NYTimes/gziphandler v1.1.1 // indirect
github.com/RoaringBitmap/roaring v1.9.3 // indirect
github.com/agext/levenshtein v1.2.1 // indirect
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 // indirect
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/apache/thrift v0.20.0 // indirect
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
@@ -269,7 +268,7 @@ require (
github.com/elazarl/goproxy v0.0.0-20240726154733-8b0c20506380 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/emicklei/proto v1.10.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect
github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
@@ -293,7 +292,7 @@ require (
github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/cel-go v0.20.1 // indirect
github.com/google/cel-go v0.21.0 // indirect
github.com/google/flatbuffers v24.3.25+incompatible // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/gofuzz v1.2.0 // indirect
@@ -306,10 +305,8 @@ require (
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect; @grafana/plugins-platform-backend
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // @grafana/identity-access-team
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-msgpack v0.5.5 // indirect
github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
github.com/hashicorp/go-sockaddr v1.0.6 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
@@ -321,9 +318,9 @@ require (
github.com/invopop/jsonschema v0.12.0 // indirect
github.com/invopop/yaml v0.3.1 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
github.com/jackc/pgx/v5 v5.5.5 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.1 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
github.com/jcmturner/gofork v1.7.6 // indirect
@@ -377,15 +374,16 @@ require (
github.com/oapi-codegen/runtime v1.1.1 // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/oklog/ulid/v2 v2.1.0 // indirect
github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/pressly/goose/v3 v3.20.0 // indirect
github.com/pressly/goose/v3 v3.22.1 // indirect
github.com/prometheus/common/sigv4 v0.1.0 // indirect
github.com/prometheus/exporter-toolkit v0.11.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
@@ -401,14 +399,14 @@ require (
github.com/segmentio/asm v1.2.0 // indirect
github.com/segmentio/encoding v0.4.0 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/sethvargo/go-retry v0.2.4 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/sethvargo/go-retry v0.3.0 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/viper v1.18.2 // indirect
github.com/spf13/viper v1.19.0 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
@@ -440,8 +438,8 @@ require (
golang.org/x/term v0.24.0 // indirect
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 // indirect; @grafana/grafana-backend-group
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
@@ -449,10 +447,10 @@ require (
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/kms v0.31.1 // indirect
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
modernc.org/libc v1.41.0 // indirect
modernc.org/libc v1.55.3 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.7.2 // indirect
modernc.org/sqlite v1.29.6 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/sqlite v1.33.1 // indirect
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect
@@ -484,6 +482,7 @@ require (
cloud.google.com/go/longrunning v0.5.12 // indirect
github.com/at-wat/mqtt-go v0.19.4 // indirect
github.com/dolthub/maphash v0.1.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/gammazero/deque v0.2.1 // indirect
github.com/grafana/grafana-app-sdk v0.19.0 // indirect
github.com/grafana/grafana/pkg/semconv v0.0.0-20240808213237-f4d2e064f435 // indirect
+79 -109
View File
@@ -1334,8 +1334,6 @@ cloud.google.com/go/workflows v1.12.1/go.mod h1:5A95OhD/edtOhQd/O741NSfIMezNTbCw
cloud.google.com/go/workflows v1.12.2/go.mod h1:+OmBIgNqYJPVggnMo9nqmizW0qEXHhmnAzK/CnBqsHc=
cloud.google.com/go/workflows v1.12.3/go.mod h1:fmOUeeqEwPzIU81foMjTRQIdwQHADi/vEr1cx9R1m5g=
cloud.google.com/go/workflows v1.12.4/go.mod h1:yQ7HUqOkdJK4duVtMeBCAOPiN1ZF1E9pAMX51vpwB/w=
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/age v1.1.1 h1:pIpO7l151hCnQ4BdyBujnGP2YlUo0uj6sAVNHGBvXHg=
filippo.io/age v1.1.1/go.mod h1:l03SrzDUrBkdBx8+IILdnn2KZysqQdbEBUQ4p3sqEQE=
@@ -1389,8 +1387,6 @@ github.com/Azure/azure-storage-blob-go v0.15.0 h1:rXtgp8tN1p29GvpGgfJetavIG0V7Og
github.com/Azure/azure-storage-blob-go v0.15.0/go.mod h1:vbjsVbX0dlxnRc4FFMPsS9BsJWPcne7GB7onqlPvz58=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw=
@@ -1453,8 +1449,6 @@ github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA4
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
@@ -1502,11 +1496,11 @@ github.com/alicebob/miniredis/v2 v2.33.0 h1:uvTF0EDeu9RLnUEG27Db5I68ESoIxTiXbNUi
github.com/alicebob/miniredis/v2 v2.33.0/go.mod h1:MhP4a3EU7aENRi9aO+tHfTBZicLqQevyi/DJpoj6mi0=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
github.com/apache/arrow/go/arrow v0.0.0-20210223225224-5bea62493d91/go.mod h1:c9sxoIT3YgLxH4UhLOCKaBlEojuMhVYpk4Ntv3opUTQ=
github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0=
github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI=
@@ -1723,8 +1717,8 @@ github.com/cncf/xds/go v0.0.0-20230428030218-4003588d1b74/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM=
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw=
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 h1:N+3sFI5GUjRKBi+i0TxYVST9h4Ie192jJWpHvthBBgg=
github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E=
github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw=
@@ -1734,9 +1728,6 @@ github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE
github.com/containerd/cgroups/v3 v3.0.1/go.mod h1:/vtwk1VXrtoa5AaZLkypuOJgA/6DyPMZHJPGQNtlHnw=
github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0=
github.com/containerd/containerd v1.2.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0=
github.com/containerd/containerd v1.7.12/go.mod h1:/5OMpE1p0ylxtEUGY8kuCYkDRzJm9NO1TFMWjUpdevk=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
@@ -1749,8 +1740,6 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
@@ -1805,8 +1794,8 @@ github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4Kfc
github.com/docker/docker v0.7.3-0.20190103212154-2b7e084dc98b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v0.7.3-0.20190817195342-4760db040282/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v26.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v26.0.2+incompatible h1:yGVmKUFGgcxA6PXWAokO0sQL22BrQ67cgVjko8tGdXE=
github.com/docker/docker v26.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
@@ -1839,6 +1828,8 @@ github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxER
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emicklei/proto v1.10.0 h1:pDGyFRVV5RvV+nkBK9iy3q67FBy9Xa7vwrOTE+g5aGw=
github.com/emicklei/proto v1.10.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -1854,8 +1845,8 @@ github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCw
github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q=
github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g=
github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0=
github.com/envoyproxy/go-control-plane v0.12.1-0.20240621013728-1eb8caab5155 h1:IgJPqnrlY2Mr4pYB6oaMKvFvwJ9H+X6CCY5x1vCTcpc=
github.com/envoyproxy/go-control-plane v0.12.1-0.20240621013728-1eb8caab5155/go.mod h1:5Wkq+JduFtdAXihLmeTJf+tRYIT4KBc2vPXDhwVo1pA=
github.com/envoyproxy/go-control-plane v0.13.0 h1:HzkeUz1Knt+3bK+8LG1bxOO/jzWZmdxpwC51i202les=
github.com/envoyproxy/go-control-plane v0.13.0/go.mod h1:GRaKG3dwvFoTg4nj7aXdZnvMg4d7nvT/wl9WgVXn3Q8=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=
@@ -1863,8 +1854,9 @@ github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6Ni
github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87KZaeN4x9zpL9Qt8fQC7d+vs=
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM=
github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb h1:IT4JYU7k4ikYg1SCxNI1/Tieq/NFvh6dzLdgi7eu0tM=
@@ -1953,8 +1945,6 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/analysis v0.21.5/go.mod h1:25YcZosX9Lwz2wBsrFrrsL8bmjjXdlyP6zsr2AMy29M=
github.com/go-openapi/analysis v0.22.0/go.mod h1:acDnkkCI2QxIo8sSIPgmp1wUlRohV7vfGtAIVae73b0=
github.com/go-openapi/analysis v0.22.2/go.mod h1:pDF4UbZsQTo/oNuRfAWWd4dAh4yuYf//LYorPTjrpvo=
@@ -2124,8 +2114,8 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84=
github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg=
github.com/google/cel-go v0.21.0 h1:cl6uW/gxN+Hy50tNYvI691+sXxioCnstFzLp2WO4GCI=
github.com/google/cel-go v0.21.0/go.mod h1:rHUlWCcBKgyEk+eV03RPdZUekPp6YcJwV0FxuUksYxc=
github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
@@ -2257,8 +2247,8 @@ github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grafana/alerting v0.0.0-20240930154843-22cee00b280e h1:RttFYx5+RTNuMPlaftx8i9f91kwUi9LdxsoPLHnticU=
github.com/grafana/alerting v0.0.0-20240930154843-22cee00b280e/go.mod h1:QsnoKX/iYZxA4Cv+H+wC7uxutBD8qi8ZW5UJvD2TYmU=
github.com/grafana/alerting v0.0.0-20241010165806-807ddf183724 h1:u+ZM5TLkdeEoSWXgYWxc4XRfPHhXpR63MyHXJxbBLrc=
github.com/grafana/alerting v0.0.0-20241010165806-807ddf183724/go.mod h1:QsnoKX/iYZxA4Cv+H+wC7uxutBD8qi8ZW5UJvD2TYmU=
github.com/grafana/authlib v0.0.0-20240919120951-58259833c564 h1:zYF/RBulpvMqPYR3gbzJZ8t/j/Eymn5FNidSYkueNCA=
github.com/grafana/authlib v0.0.0-20240919120951-58259833c564/go.mod h1:PFzXbCrn0GIpN4KwT6NP1l5Z1CPLfmKHnYx8rZzQcyY=
github.com/grafana/authlib/claims v0.0.0-20240827210201-19d5347dd8dd h1:sIlR7n38/MnZvX2qxDEszywXdI5soCwQ78aTDSARvus=
@@ -2396,8 +2386,8 @@ github.com/hashicorp/go-plugin v1.6.1/go.mod h1:XPHFku2tFo3o3QKFgSYo+cghcUhw1NA1
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
@@ -2490,13 +2480,13 @@ github.com/ionos-cloud/sdk-go/v6 v6.1.11/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLj
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs=
github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
@@ -2621,8 +2611,6 @@ github.com/linkedin/goavro/v2 v2.10.0 h1:eTBIRoInBM88gITGXYtUSqqxLTFXfOsJBiX8ZMW
github.com/linkedin/goavro/v2 v2.10.0/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA=
github.com/linode/linodego v1.32.0 h1:OmZzB3iON6uu84VtLFf64uKmAQqJJarvmsVguroioPI=
github.com/linode/linodego v1.32.0/go.mod h1:y8GDP9uLVH4jTB9qyrgw79qfKdYJmNCGUOJmfuiOcmI=
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c h1:VtwQ41oftZwlMnOEbMWQtSEUgU64U4s+GHk7hZK+jtY=
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o=
@@ -2690,8 +2678,8 @@ github.com/maypok86/otter v1.2.2 h1:jJi0y8ruR/ZcKmJ4FbQj3QQTqKwV+LNrSOo2S1zbF5M=
github.com/maypok86/otter v1.2.2/go.mod h1:mKLfoI7v1HOmQMwFgX4QkRk23mX6ge3RDvjdHOWG4R4=
github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
github.com/microsoft/go-mssqldb v1.7.0 h1:sgMPW0HA6Ihd37Yx0MzHyKD726C2kY/8KJsQtXHNaAs=
github.com/microsoft/go-mssqldb v1.7.0/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA=
github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA=
github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
@@ -2750,18 +2738,10 @@ github.com/mithrandie/ternary v1.1.1 h1:k/joD6UGVYxHixYmSR8EGgDFNONBMqyD373xT4QR
github.com/mithrandie/ternary v1.1.1/go.mod h1:0D9Ba3+09K2TdSZO7/bFCC0GjSXetCvYuYq0u8FY/1g=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8=
github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/mocktools/go-smtp-mock/v2 v2.3.1 h1:wq75NDSsOy5oHo/gEQQT0fRRaYKRqr1IdkjhIPXxagM=
github.com/mocktools/go-smtp-mock/v2 v2.3.1/go.mod h1:h9AOf/IXLSU2m/1u4zsjtOM/WddPwdOUBz56dV9f81M=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -2778,7 +2758,6 @@ github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJ
github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de h1:D5x39vF5KCwKQaw+OC9ZPiLVHXz3UFw2+psEX+gYcto=
github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de/go.mod h1:kJun4WP5gFuHZgRjZUWWuH1DTxCtxbHDOIJsudS8jzY=
@@ -2885,12 +2864,12 @@ github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/openfga/api/proto v0.0.0-20240529184453-5b0b4941f3e0 h1:tSJl/atdqsDACjRQQPCbXe2GfEvcOkhdrUNmDToAjTA=
github.com/openfga/api/proto v0.0.0-20240529184453-5b0b4941f3e0/go.mod h1:XnvYrdU//9i70Aou6n4H5DJ0bdRPB3IlmE/Vx6qhnm8=
github.com/openfga/language/pkg/go v0.0.0-20240409225820-a53ea2892d6d h1:n44DfITs+CLCYJIgsryJkG2ElwOZJ3huekPZKydPi7U=
github.com/openfga/language/pkg/go v0.0.0-20240409225820-a53ea2892d6d/go.mod h1:wkI4GcY3yNNuFMU2ncHPWqBaF7XylQTkJYfBi2pIpK8=
github.com/openfga/openfga v1.5.4 h1:mVrp0uB9jNWX/5+OtZLM6YOx5Y9Y4r/D/O+LNBF/FGQ=
github.com/openfga/openfga v1.5.4/go.mod h1:+PoZg9BJeq+h3L0eR52tqNTwghSapCFtmaVKHsUK7QM=
github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66 h1:pAYrdyIKxPsMs/nRcTEnS9za2io11g7Rt7ng7HK82hk=
github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66/go.mod h1:gil5LBD8tSdFQbUkCQdnXsoeU9kDJdJgbGdHkgJfcd0=
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f h1:ZMZ7ntMnaHIPZxvVQv/aqC4ctzLqH+9Fqn4uw35kQpk=
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f/go.mod h1:ll/hN6kS4EE6B/7J/PbZqac9Nuv7ZHpI+Jfh36JLrbs=
github.com/openfga/openfga v1.6.2 h1:tHBAgiCPomCZb3IH0CFqOpTDVDA/Xb8kG87oX4JCbXc=
github.com/openfga/openfga v1.6.2/go.mod h1:jzbEpheazf6MFjtanQt1rpxexSRzfa9057F7JlkMv2I=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w=
github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU=
@@ -2919,8 +2898,8 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM=
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
@@ -2956,11 +2935,9 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c h1:NRoLoZvkBTKvR5gQLgA3e0hqjkY9u1wm+iOL45VN/qI=
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/pressly/goose/v3 v3.20.0 h1:uPJdOxF/Ipj7ABVNOAMJXSxwFXZGwMGHNqjC8e61VA0=
github.com/pressly/goose/v3 v3.20.0/go.mod h1:BRfF2GcG4FTG12QfdBVy3q1yveaf4ckL9vWwEcIO3lA=
github.com/pressly/goose/v3 v3.22.1 h1:2zICEfr1O3yTP9BRZMGPj7qFxQ+ik6yeo+z1LMuioLc=
github.com/pressly/goose/v3 v3.22.1/go.mod h1:xtMpbstWyCpyH+0cxLTMCENWBG+0CSxvTsXhW95d5eo=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
@@ -2977,8 +2954,8 @@ github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4=
github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI=
github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@@ -3093,19 +3070,15 @@ github.com/segmentio/encoding v0.4.0 h1:MEBYvRqiUB2nfR2criEXWqwdY6HJOUrCn5hboVOV
github.com/segmentio/encoding v0.4.0/go.mod h1:/d03Cd8PoaDeceuhUUUQWjU0KhWjrmYrWPgtJHYZSnI=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec=
github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw=
github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE=
github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas=
github.com/shadowspore/fossil-delta v0.0.0-20240102155221-e3a8590b820b h1:SCYeryKXBVdW38167VyumGakH+7E4Wxe6b/zxmQxwyM=
github.com/shadowspore/fossil-delta v0.0.0-20240102155221-e3a8590b820b/go.mod h1:daNLfX/GJKuZyN4HkMf0h8dVmTmgRbBSkd9bFQyGNIo=
github.com/shirou/gopsutil/v3 v3.24.2 h1:kcR0erMbLg5/3LcInpw0X/rrPSqq4CDPyI6A6ZRC18Y=
github.com/shirou/gopsutil/v3 v3.24.2/go.mod h1:tSg/594BcA+8UdQU2XcW803GWYgdtauFFPgJCJKZlVk=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v1.7.1/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs=
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1qZoYLZzLnBw+QkPP9WZnjlSWihhxAJC1+/M=
@@ -3159,8 +3132,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw=
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/spyzhov/ajson v0.9.0 h1:tF46gJGOenYVj+k9K1U1XpCxVWhmiyY5PsVCAs1+OJ0=
github.com/spyzhov/ajson v0.9.0/go.mod h1:a6oSw0MMb7Z5aD2tPoPO+jq11ETKgXUr2XktHdT8Wt8=
@@ -3200,19 +3173,9 @@ github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSW
github.com/substrait-io/substrait-go v0.4.2/go.mod h1:qhpnLmrcvAnlZsUyPXZRqldiHapPTXC3t7xFgDi3aQg=
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf h1:Z2X3Os7oRzpdJ75iPqWZc0HeJWFYNCvKsfpQwFpRNTA=
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0=
github.com/testcontainers/testcontainers-go v0.30.0 h1:jmn/XS22q4YRrcMwWg0pAwlClzs/abopbsBzrepyc4E=
github.com/testcontainers/testcontainers-go v0.30.0/go.mod h1:K+kHNGiM5zjklKjgTtcrEetF3uhWbMUyqAQoyoh8Pf0=
github.com/testcontainers/testcontainers-go/modules/mysql v0.30.0 h1:wrePvxfU/2HFALKyBqpNs6VoPPvThzHy9aN+PCxse9g=
github.com/testcontainers/testcontainers-go/modules/mysql v0.30.0/go.mod h1:Srnlf7wwA7s6K4sKKhjAoBHJcKorRINR/i5dCA4ZyGk=
github.com/testcontainers/testcontainers-go/modules/postgres v0.30.0 h1:D3HFqpZS90iRGAN7M85DFiuhPfvYvFNnx8urQ6mPAvo=
github.com/testcontainers/testcontainers-go/modules/postgres v0.30.0/go.mod h1:e1sKxwUOkqzvaqdHl/oV9mUtFmkDPTfBGp0po2tnWQU=
github.com/thanos-io/objstore v0.0.0-20220809103346-8ef1f215e2bf h1:onQsPyHlq2yIWU+Nfl6yStuqnZuVQQN8FZ8sBb2wqtw=
github.com/thanos-io/objstore v0.0.0-20220809103346-8ef1f215e2bf/go.mod h1:v0NhuxxxUFUPatQcVNSCUkBEVezXzl7LSdaBOZygq98=
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk=
@@ -3282,8 +3245,6 @@ github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zclconf/go-cty v1.13.0 h1:It5dfKTTZHe9aeppbNOda3mN7Ag7sg6QkBNm6TkyFa0=
github.com/zclconf/go-cty v1.13.0/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
@@ -3343,8 +3304,8 @@ go.opentelemetry.io/collector/semconv v0.98.0/go.mod h1:8ElcRZ8Cdw5JnvhTOQOdYizk
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 h1:hCq2hNMwsegUvPzI7sPOvtO9cqyy5GbWt/Ybp2xrx8Q=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0/go.mod h1:LqaApwGx/oUmzsbqxkzuBvyoPpkxk3JQWnqfVrJ3wCA=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.55.0 h1:sqmsIQ75l6lfZjjpnXXT9DFVtYEDg6CH0/Cn4/3A1Wg=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.55.0/go.mod h1:rsg1EO8LXSs2po50PB5CeY/MSVlhghuKBgXlKnqm6ks=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo=
@@ -3369,11 +3330,11 @@ go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDI
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4=
go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0/go.mod h1:h95q0LBGh7hlAC08X2DhSeyIG02YQ0UyioTCVAqRPmc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 h1:lsInsfvhVIfOI6qHVyysXMNDnjO9Npvl7tlDPJFBVd4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0/go.mod h1:KQsVNh4OjgjTG0G6EiNi1jVpnaeeKsKMRwbLN+f1+8M=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0/go.mod h1:8GlBGcDk8KKi7n+2S4BT/CPZQYH3erLu0/k64r1MYgo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 h1:m0yTiGDLUvVYaTFbAvCkVYIYcvwKt3G7OLoN77NUs/8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0/go.mod h1:wBQbT4UekBfegL2nx0Xk1vBcnzyBPsIVm9hRG4fYcr4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0/go.mod h1:e7ciERRhZaOZXVjx5MiL8TK5+Xv7G5Gv5PA2ZDEJdL8=
go.opentelemetry.io/otel/metric v1.17.0/go.mod h1:h4skoxdZI17AxwITdmdZjjYJQH5nzijUUjm+wtPph5o=
go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8=
@@ -3388,8 +3349,8 @@ go.opentelemetry.io/otel/sdk v1.17.0/go.mod h1:U87sE0f5vQB7hwUoW98pW5Rz4ZDuCFBZF
go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw=
go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo=
go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE=
go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg=
go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY=
go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
@@ -3509,8 +3470,8 @@ golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N0
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -4048,8 +4009,8 @@ gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0=
gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA=
gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY=
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU=
gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0=
gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY=
@@ -4347,8 +4308,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20240213162025-012b6fc9bca9/go.
google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8=
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y=
google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be/go.mod h1:dvdCTIoAGbkWbcIKBniID56/7XHTt6WfxXNMxuziJ+w=
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo=
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g=
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc=
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20230807174057-1744710a1577/go.mod h1:NjCQG/D8JandXxM57PZbAJL1DCNL6EypA0vPPwfsc7c=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20231030173426-d783a09b4405/go.mod h1:GRUCuLdzVqZte8+Dl/D4N25yLzcGqqWaYkeVOwulFqw=
@@ -4393,8 +4354,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2/go.
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240415141817-7cd4c1c1f9ec/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
@@ -4460,8 +4421,8 @@ google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJai
google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw=
google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200910201057-6591123024b3/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
@@ -4591,6 +4552,8 @@ modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20=
modernc.org/cc/v3 v3.38.1/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20=
modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=
modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=
modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw=
modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI=
@@ -4601,9 +4564,13 @@ modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aw
modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo=
modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g=
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y=
modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
@@ -4622,8 +4589,8 @@ modernc.org/libc v1.21.2/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI=
modernc.org/libc v1.21.4/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI=
modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug=
modernc.org/libc v1.22.4/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
modernc.org/libc v1.41.0 h1:g9YAc6BkKlgORsUWj+JwqoB1wU3o4DE3bM3yvA3k+Gk=
modernc.org/libc v1.41.0/go.mod h1:w0eszPsiXoOnoMJgrXjglgLuDy/bt5RR4y3QzUUeodY=
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
@@ -4635,15 +4602,18 @@ modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/memory v1.3.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4=
modernc.org/sqlite v1.18.2/go.mod h1:kvrTLEWgxUcHa2GfHBQtanR1H9ht3hTJNtKpzH9k1u0=
modernc.org/sqlite v1.21.2/go.mod h1:cxbLkB5WS32DnQqeH4h4o1B0eMr8W/y8/RGuxQ3JsC0=
modernc.org/sqlite v1.29.6 h1:0lOXGrycJPptfHDuohfYgNqoe4hu+gYuN/pKgY5XjS4=
modernc.org/sqlite v1.29.6/go.mod h1:S02dvcmm7TnTRvGhv8IGYyLnIt7AS2KPaB1F/71p75U=
modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM=
modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
+97 -6
View File
@@ -2,6 +2,8 @@ buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-2023080216373
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230802163732-1c33ebd9ecfa.1/go.mod h1:xafc+XIsTxTy76GJQ1TKgvJWsSugFBqMaN27WhUblew=
cel.dev/expr v0.15.0 h1:O1jzfJCQBfL5BFoYktaxwIhuttaQPsVWerH9/EEKx0w=
cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg=
cel.dev/expr v0.16.0 h1:yloc84fytn4zmJX2GU3TkXGsaieaV7dQ057Qs4sIG2Y=
cel.dev/expr v0.16.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg=
cloud.google.com/go/accessapproval v1.7.11 h1:MgtE8CI+YJWPGGHnxQ9z1VQqV87h+vSGy2MeM/m0ggQ=
cloud.google.com/go/accessapproval v1.7.11/go.mod h1:KGK3+CLDWm4BvjN0wFtZqdFUGhxlTvTF6PhAwQJGL4M=
cloud.google.com/go/accesscontextmanager v1.8.11 h1:IQ3KLJmNKPgstN0ZcRw0niU4KfsiOZmzvcGCF+NT618=
@@ -259,7 +261,19 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUu
docker.io/go-docker v1.0.0 h1:VdXS/aNYQxyA9wdLD5z8Q8Ro688/hG8HzKxYVEVbE6s=
docker.io/go-docker v1.0.0/go.mod h1:7tiAn5a0LFmjbPDbyTPOaTTOuG1ZRNXdPA6RvKY+fpY=
gioui.org v0.0.0-20210308172011-57750fc8a0a6 h1:K72hopUosKG3ntOPNG4OzzbuhxGuVf06fa2la1/H/Ho=
gioui.org v0.2.0 h1:RbzDn1h/pCVf/q44ImQSa/J3MIFpY3OWphzT/Tyei+w=
gioui.org v0.2.0/go.mod h1:1H72sKEk/fNFV+l0JNeM2Dt3co3Y4uaQcD+I+/GQ0e4=
gioui.org/cpu v0.0.0-20220412190645-f1e9e8c3b1f7 h1:tNJdnP5CgM39PRc+KWmBRRYX/zJ+rd5XaYxY5d5veqA=
gioui.org/cpu v0.0.0-20220412190645-f1e9e8c3b1f7/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
gioui.org/shader v1.0.6 h1:cvZmU+eODFR2545X+/8XucgZdTtEjR3QWW6W65b0q5Y=
gioui.org/shader v1.0.6/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
gioui.org/x v0.2.0 h1:/MbdjKH19F16auv19UiQxli2n6BYPw7eyh9XBOTgmEw=
gioui.org/x v0.2.0/go.mod h1:rCGN2nZ8ZHqrtseJoQxCMZpt2xrZUrdZ2WuMRLBJmYs=
git.sr.ht/~sbinet/cmpimg v0.1.0 h1:E0zPRk2muWuCqSKSVZIWsgtU9pjsw3eKHi8VmQeScxo=
git.sr.ht/~sbinet/cmpimg v0.1.0/go.mod h1:FU12psLbF4TfNXkKH2ZZQ29crIqoiqTZmeQ7dkp/pxE=
git.sr.ht/~sbinet/gg v0.3.1 h1:LNhjNn8DerC8f9DHLz6lS0YYul/b602DUxDgGkd/Aik=
git.sr.ht/~sbinet/gg v0.5.0 h1:6V43j30HM623V329xA9Ntq+WJrMjDxRjuAB1LFWF5m8=
git.sr.ht/~sbinet/gg v0.5.0/go.mod h1:G2C0eRESqlKhS7ErsNey6HHrqU1PwsnCQlekFi9Q2Oo=
github.com/99designs/basicauth-go v0.0.0-20160802081356-2a93ba0f464d h1:j6oB/WPCigdOkxtuPl1VSIiLpy7Mdsu6phQffbF19Ng=
github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e h1:rl2Aq4ZODqTDkeSqQBy+fzpZPamacO1Srp8zq7jf2Sc=
github.com/Azure/azure-amqp-common-go/v3 v3.2.3 h1:uDF62mbd9bypXWi19V1bN5NZEO84JqgmI5G73ibAmrk=
@@ -281,8 +295,12 @@ github.com/Azure/go-autorest/autorest/azure/cli v0.4.5/go.mod h1:ADQAXrkgm7acgWV
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc=
github.com/ClickHouse/ch-go v0.58.2 h1:jSm2szHbT9MCAB1rJ3WuCJqmGLi5UTjlNu+f530UTS0=
github.com/ClickHouse/ch-go v0.58.2/go.mod h1:Ap/0bEmiLa14gYjCiRkYGbXvbe8vwdrfTYWhsuQ99aw=
github.com/ClickHouse/ch-go v0.61.5 h1:zwR8QbYI0tsMiEcze/uIMK+Tz1D3XZXLdNrlaOpeEI4=
github.com/ClickHouse/ch-go v0.61.5/go.mod h1:s1LJW/F/LcFs5HJnuogFMta50kKDO0lf9zzfrbl0RQg=
github.com/ClickHouse/clickhouse-go/v2 v2.17.1 h1:ZCmAYWpu75IyEi7+Yrs/uaAjiCGY5wfW5kXo64exkX4=
github.com/ClickHouse/clickhouse-go/v2 v2.17.1/go.mod h1:rkGTvFDTLqLIm0ma+13xmcCfr/08Gvs7KmFt1tgiWHQ=
github.com/ClickHouse/clickhouse-go/v2 v2.28.3 h1:SkFzPULX6nzgfNZd1YD1XTECivjTMrCtD09ZPKcVLFQ=
github.com/ClickHouse/clickhouse-go/v2 v2.28.3/go.mod h1:vzn73hp+3JwxtFU4RjPCQ7r6fP2pMKVwdi8E1/Tkua8=
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c=
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME=
@@ -300,6 +318,8 @@ github.com/KimMachineGun/automemlimit v0.6.0 h1:p/BXkH+K40Hax+PuWWPQ478hPjsp9h1C
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
github.com/MicahParks/keyfunc v1.9.0 h1:lhKd5xrFHLNOWrDc4Tyb/Q1AJ4LCzQ48GVJyVIID3+o=
github.com/MicahParks/keyfunc v1.9.0/go.mod h1:IdnCilugA0O/99dW+/MkvlyrsX8+L8+x95xuVNtM5jw=
github.com/MicahParks/keyfunc/v2 v2.1.0 h1:6ZXKb9Rp6qp1bDbJefnG7cTH8yMN1IC/4nf+GVjO99k=
github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
github.com/OneOfOne/xxhash v1.2.6 h1:U68crOE3y3MPttCMQGywZOLrTeF5HHJ3/vDBCJn9/bA=
github.com/OneOfOne/xxhash v1.2.6/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
@@ -335,10 +355,10 @@ github.com/alexflint/go-scalar v1.0.0 h1:NGupf1XV/Xb04wXskDFzS0KWOLH632W/EO4fAFi
github.com/alexflint/go-scalar v1.0.0/go.mod h1:GpHzbCOZXEKMEcygYQ5n/aa4Aq84zbxjy3MxYW0gjYw=
github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI=
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/andybalholm/stroke v0.0.0-20221221101821-bd29b49d73f0 h1:uF5Q/hWnDU1XZeT6CsrRSxHLroUSEYYO3kgES+yd+So=
github.com/andybalholm/stroke v0.0.0-20221221101821-bd29b49d73f0/go.mod h1:ccdDYaY5+gO+cbnQdFxEXqfy0RkoV25H3jLXUDNM3wg=
github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 h1:goHVqTbFX3AIo0tzGr14pgfAW2ZfPChKO21Z9MGf/gk=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
@@ -395,6 +415,8 @@ github.com/bufbuild/protovalidate-go v0.2.1/go.mod h1:e7XXDtlxj5vlEyAgsrxpzayp4c
github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw=
github.com/bytedance/sonic v1.10.0-rc3 h1:uNSnscRapXTwUgTyOF0GVljYD08p9X/Lbr9MweSV3V0=
github.com/bytedance/sonic v1.10.0-rc3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
github.com/campoy/embedmd v1.0.0 h1:V4kI2qTJJLf4J29RzI/MAt2c3Bl4dQSYPuflzwFH2hY=
github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8=
github.com/casbin/casbin/v2 v2.37.0 h1:/poEwPSovi4bTOcP752/CsTQiRz2xycyVKFG7GUhbDw=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
@@ -426,7 +448,11 @@ github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9D
github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ=
github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=
github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0=
github.com/containerd/containerd v1.6.8 h1:h4dOFDwzHmqFEP754PgfgTeVXFnLiRc6kiqC7tplDJs=
github.com/containerd/containerd v1.6.8/go.mod h1:By6p5KqPK0/7/CgO/A6t/Gz+CUYUu2zf1hUaaymVXB0=
github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04=
github.com/coreos/go-etcd v2.0.0+incompatible h1:bXhRBIXoTm9BYHS3gE0TtQuyNZyeEMux2sDi4oo5YOo=
github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk=
@@ -492,6 +518,7 @@ github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQ
github.com/elazarl/goproxy v0.0.0-20230731152917-f99041a5c027/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/expr-lang/expr v1.16.2 h1:JvMnzUs3LeVHBvGFcXYmXo+Q6DPDmzrlcSBO6Wy3w4s=
github.com/expr-lang/expr v1.16.2/go.mod h1:uCkhfG+x7fcZ5A5sXHKuQ07jGZRl6J0FCAaf2k4PtVQ=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
@@ -518,20 +545,36 @@ github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=
github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw=
github.com/go-faster/errors v0.6.1 h1:nNIPOBkprlKzkThvS/0YaX8Zs9KewLCOSFQS5BU06FI=
github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+Jpi2LAyY=
github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg=
github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo=
github.com/go-fonts/dejavu v0.1.0 h1:JSajPXURYqpr+Cu8U9bt8K+XcACIHWqWrvWCKyeFmVQ=
github.com/go-fonts/dejavu v0.3.2 h1:3XlHi0JBYX+Cp8n98c6qSoHrxPa4AUKDMKdrh/0sUdk=
github.com/go-fonts/dejavu v0.3.2/go.mod h1:m+TzKY7ZEl09/a17t1593E4VYW8L1VaBXHzFZOIjGEY=
github.com/go-fonts/latin-modern v0.2.0 h1:5/Tv1Ek/QCr20C6ZOz15vw3g7GELYL98KWr8Hgo+3vk=
github.com/go-fonts/latin-modern v0.3.2 h1:M+Sq24Dp0ZRPf3TctPnG1MZxRblqyWC/cRUL9WmdaFc=
github.com/go-fonts/latin-modern v0.3.2/go.mod h1:9odJt4NbRrbdj4UAMuLVd4zEukf6aAEKnDaQga0whqQ=
github.com/go-fonts/liberation v0.3.0 h1:3BI2iaE7R/s6uUUtzNCjo3QijJu3aS4wmrMgfSpYQ+8=
github.com/go-fonts/liberation v0.3.0/go.mod h1:jdJ+cqF+F4SUL2V+qxBth8fvBpBDS7yloUL5Fi8GTGY=
github.com/go-fonts/liberation v0.3.2 h1:XuwG0vGHFBPRRI8Qwbi5tIvR3cku9LUfZGq/Ar16wlQ=
github.com/go-fonts/liberation v0.3.2/go.mod h1:N0QsDLVUQPy3UYg9XAc3Uh3UDMp2Z7M1o4+X98dXkmI=
github.com/go-fonts/stix v0.1.0 h1:UlZlgrvvmT/58o573ot7NFw0vZasZ5I6bcIft/oMdgg=
github.com/go-fonts/stix v0.2.2 h1:v9krocr13J1llaOHLEol1eaHsv8S43UuFX/1bFgEJJ4=
github.com/go-fonts/stix v0.2.2/go.mod h1:SUxggC9dxd/Q+rb5PkJuvfvTbOPtNc2Qaua00fIp9iU=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I=
github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU=
github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg=
github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9 h1:NxXI5pTAtpEaU49bpLpQoDsu1zrteW/vxzTz8Cd2UAs=
github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9/go.mod h1:gWuR/CrFDDeVRFQwHPvsv9soJVB/iqymhuZQuJ3a9OM=
github.com/go-latex/latex v0.0.0-20231108140139-5c1ce85aa4ea h1:DfZQkvEbdmOe+JK2TMtBM+0I9GSdzE2y/L1/AmD8xKc=
github.com/go-latex/latex v0.0.0-20231108140139-5c1ce85aa4ea/go.mod h1:Y7Vld91/HRbTBm7JwoI7HejdDB0u+e9AUBO9MB7yuZk=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.22.8/go.mod h1:6QT22icPLEqAM/z/TChgb4WAveCHF92+2gF0CNjHpPI=
github.com/go-pdf/fpdf v0.6.0 h1:MlgtGIfsdMEEQJr2le6b/HNr1ZlQwxyWr77r2aj2U/8=
github.com/go-pdf/fpdf v0.9.0 h1:PPvSaUuo1iMi9KkaAn90NuKi+P4gwMedWPHhj8YlJQw=
github.com/go-pdf/fpdf v0.9.0/go.mod h1:oO8N111TkmKb9D7VvWGLvLJlaZUQVPM+6V42pp3iV4Y=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
@@ -539,6 +582,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-text/typesetting v0.0.0-20230803102845-24e03d8b5372 h1:FQivqchis6bE2/9uF70M2gmmLpe82esEm2QadL0TEJo=
github.com/go-text/typesetting v0.0.0-20230803102845-24e03d8b5372/go.mod h1:evDBbvNR/KaVFZ2ZlDSOWWXIUKq0wCOEtzLxRM8SG3k=
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsMBaUOKXq6HSv655U1c=
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
@@ -554,6 +599,8 @@ github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfE
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4=
github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY=
github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386 h1:EcQR3gusLHN46TAD+G+EbaaqJArt5vHhNpXAa12PQf4=
github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws=
@@ -585,8 +632,6 @@ github.com/grafana/alerting v0.0.0-20240830172655-aa466962ea18/go.mod h1:GMLi6d0
github.com/grafana/alerting v0.0.0-20240917171353-6c25eb6eff10 h1:oDbLKM34O+JUF9EQFS+9aYhdYoeNfUpXqNjFCLIxwF4=
github.com/grafana/alerting v0.0.0-20240917171353-6c25eb6eff10/go.mod h1:GMLi6d09Xqo96fCVUjNk//rcjP5NKEdjOzfWIffD5r4=
github.com/grafana/gomemcache v0.0.0-20240229205252-cd6a66d6fb56/go.mod h1:PGk3RjYHpxMM8HFPhKKo+vve3DdlPUELZLSDEFehPuU=
github.com/grafana/prometheus-alertmanager v0.25.1-0.20240625192351-66ec17e3aa45 h1:AJKOtDKAOg8XNFnIZSmqqqutoTSxVlRs6vekL2p2KEY=
github.com/grafana/prometheus-alertmanager v0.25.1-0.20240625192351-66ec17e3aa45/go.mod h1:01sXtHoRwI8W324IPAzuxDFOmALqYLCOhvSC2fUHWXc=
github.com/grafana/pyroscope-go/godeltaprof v0.1.6/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE=
github.com/grafana/thema v0.0.0-20230511182720-3146087fcc26 h1:HX927q4X1n451pnGb8U0wq74i8PCzuxVjzv7TyD10kc=
github.com/grafana/thema v0.0.0-20230511182720-3146087fcc26/go.mod h1:Pn9nfzCk7nV0mvNgwusgCjCROZP6nm4GpwTnmEhLT24=
@@ -689,8 +734,12 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b
github.com/lightstep/lightstep-tracer-go v0.18.1 h1:vi1F1IQ8N7hNWytK9DpJsUfQhGuNSc19z330K6vl4zk=
github.com/logrusorgru/aurora/v3 v3.0.0 h1:R6zcoZZbvVcGMvDCKo45A9U/lzYyzl5NfYIvznmDfE4=
github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc=
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c h1:VtwQ41oftZwlMnOEbMWQtSEUgU64U4s+GHk7hZK+jtY=
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
github.com/lyft/protoc-gen-star v0.6.1 h1:erE0rdztuaDq3bpGifD95wfoPrSZc95nGA6tbiNYh6M=
github.com/lyft/protoc-gen-star/v2 v2.0.3 h1:/3+/2sWyXeMLzKd1bX+ixWKgEMsULrIivpDsuaF441o=
github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4 h1:sIXJOMrYnQZJu7OB7ANSF4MYri2fTEGIsRLz6LwI4xE=
github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk=
github.com/lyft/protoc-gen-validate v0.0.13 h1:KNt/RhmQTOLr7Aj8PsJ7mTronaFyx80mRTT9qF261dA=
github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw=
github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18=
@@ -700,6 +749,8 @@ github.com/matryer/moq v0.5.0 h1:h2PJUYjZSiyEahzVogDRmrgL9Bsx9xYAl8l+LPfmwL8=
github.com/matryer/moq v0.5.0/go.mod h1:39GTnrD0mVWHPvWdYj5ki/lxfhLQEtHcLh+tWoYF/iE=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g=
github.com/mfridman/xflag v0.0.0-20240825232106-efb77353e578 h1:CRrqlUmLebb/QjzRDWE0E66+YyN/v95+w6WyH9ju8/Y=
github.com/mfridman/xflag v0.0.0-20240825232106-efb77353e578/go.mod h1:/483ywM5ZO5SuMVjrIGquYNE5CzLrj5Ux/LxWWnjRaE=
github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg=
github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
@@ -722,8 +773,12 @@ github.com/nats-io/jwt/v2 v2.0.3 h1:i/O6cmIsjpcQyWDYNcq2JyZ3/VTF8SJ4JWluI5OhpvI=
github.com/nats-io/nats-server/v2 v2.5.0 h1:wsnVaaXH9VRSg+A2MVg5Q727/CqxnmPLGFQ3YZYKTQg=
github.com/nats-io/nats.go v1.31.0 h1:/WFBHEc/dOKBF6qf1TZhrdEfTmOZ5JzdJ+Y3m6Y/p7E=
github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8=
github.com/nats-io/nats.go v1.34.0 h1:fnxnPCNiwIG5w08rlMcEKTUw4AV/nKyGCOJE8TdhSPk=
github.com/nats-io/nats.go v1.34.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY=
github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts=
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1 h1:dOYG7LS/WK00RWZc8XGgcUTlTxpp3mKhdR2Q9z9HbXM=
@@ -782,6 +837,8 @@ github.com/parquet-go/parquet-go v0.20.2-0.20240416173845-962b3c5827c3 h1:dHzXGq
github.com/parquet-go/parquet-go v0.20.2-0.20240416173845-962b3c5827c3/go.mod h1:wMYanjuaE900FTDTNY00JU+67Oqh9uO0pYWRNoPGctQ=
github.com/paulmach/orb v0.10.0 h1:guVYVqzxHE/CQ1KpfGO077TR0ATHSNjp4s6XGLn3W9s=
github.com/paulmach/orb v0.10.0/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU=
github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30 h1:BHT1/DKsYDGkUgQ2jmMaozVcdk+sVfz0+1ZJq4zkWgw=
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
@@ -800,6 +857,8 @@ github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDj
github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo=
github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk=
github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo=
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c h1:NRoLoZvkBTKvR5gQLgA3e0hqjkY9u1wm+iOL45VN/qI=
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc=
github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
@@ -823,6 +882,8 @@ github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245 h1:K1Xf3bKttbF
github.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF25UfsK2X7Ph/zCAk=
github.com/sagikazarmark/crypt v0.17.0 h1:ZA/7pXyjkHoK4bW4mIdnCLvL8hd+Nrbiw7Dqk7D4qUk=
github.com/sagikazarmark/crypt v0.17.0/go.mod h1:SMtHTvdmsZMuY/bpZoqokSoChIrcJ/epOxZN58PbZDg=
github.com/sagikazarmark/crypt v0.19.0 h1:WMyLTjHBo64UvNcWqpzY3pbZTYgnemZU8FBZigKc42E=
github.com/sagikazarmark/crypt v0.19.0/go.mod h1:c6vimRziqqERhtSe0MhIvzE1w54FrCHtrXb5NH/ja78=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da h1:p3Vo3i64TCLY7gIfzeQaUJ+kppEO5WQG3cL8iE8tGHU=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk=
@@ -834,6 +895,10 @@ github.com/segmentio/fasthash v0.0.0-20180216231524-a72b379d632e/go.mod h1:tm/wZ
github.com/sercand/kuberesolver/v5 v5.1.1 h1:CYH+d67G0sGBj7q5wLK61yzqJJ8gLLC8aeprPTHb6yY=
github.com/sercand/kuberesolver/v5 v5.1.1/go.mod h1:Fs1KbKhVRnB2aDWN12NjKCB+RgYMWZJ294T3BtmVCpQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shirou/gopsutil/v3 v3.24.2 h1:kcR0erMbLg5/3LcInpw0X/rrPSqq4CDPyI6A6ZRC18Y=
github.com/shirou/gopsutil/v3 v3.24.2/go.mod h1:tSg/594BcA+8UdQU2XcW803GWYgdtauFFPgJCJKZlVk=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v1.7.1 h1:UJcjSAI3aUKx52kfcfhblgyhZceouhvvs3OYdWgn+PY=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/sony/gobreaker v0.4.1 h1:oMnRNZXX5j85zso6xCPRNPtmAycat+WcoKbklScLDgQ=
@@ -854,14 +919,22 @@ github.com/tdewolff/parse/v2 v2.6.8 h1:mhNZXYCx//xG7Yq2e/kVLNZw4YfYmeHbhx+Zc0OvF
github.com/tdewolff/parse/v2 v2.6.8/go.mod h1:XHDhaU6IBgsryfdnpzUXBlT6leW/l25yrFBTEb4eIyM=
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94=
github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/tursodatabase/libsql-client-go v0.0.0-20240411070317-a1138d155304 h1:Y6cw8yjWCEJDy5Bll7HjTinkgTQU55AXiKSEe29SpgA=
github.com/tursodatabase/libsql-client-go v0.0.0-20240411070317-a1138d155304/go.mod h1:2Fu26tjM011BLeR5+jwTfs6DX/fNMEWV/3CBZvggrA4=
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d h1:dOMI4+zEbDI37KGb0TI44GUAwxHF9cMsIoDTJ7UmgfU=
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d/go.mod h1:l8xTsYB90uaVdMHXMCxKKLSgw5wLYBwBKKefNIUnm9s=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
@@ -903,12 +976,18 @@ github.com/yalue/merged_fs v1.3.0 h1:qCeh9tMPNy/i8cwDsQTJ5bLr6IRxbs6meakNE5O+wyY
github.com/yalue/merged_fs v1.3.0/go.mod h1:WqqchfVYQyclV2tnR7wtRhBddzBvLVR83Cjw9BKQw0M=
github.com/ydb-platform/ydb-go-genproto v0.0.0-20240126124512-dbb0e1720dbf h1:ckwNHVo4bv2tqNkgx3W3HANh3ta1j6TR5qw08J1A7Tw=
github.com/ydb-platform/ydb-go-genproto v0.0.0-20240126124512-dbb0e1720dbf/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I=
github.com/ydb-platform/ydb-go-genproto v0.0.0-20240528144234-5d5a685e41f7 h1:nL8XwD6fSst7xFUirkaWJmE7kM0CdWRYgu6+YQer1d4=
github.com/ydb-platform/ydb-go-genproto v0.0.0-20240528144234-5d5a685e41f7/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I=
github.com/ydb-platform/ydb-go-sdk/v3 v3.55.1 h1:Ebo6J5AMXgJ3A438ECYotA0aK7ETqjQx9WoZvVxzKBE=
github.com/ydb-platform/ydb-go-sdk/v3 v3.55.1/go.mod h1:udNPW8eupyH/EZocecFmaSNJacKKYjzQa7cVgX5U2nc=
github.com/ydb-platform/ydb-go-sdk/v3 v3.80.2 h1:qmZGJQCNx09/r0HDIT2cDDogiOvWikELy13ubM2CFS8=
github.com/ydb-platform/ydb-go-sdk/v3 v3.80.2/go.mod h1:IHwuXyolaAmGK2Dp7+dlhsnXphG1pwCoaP/OITT3+tU=
github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA=
github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI=
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
github.com/zenazn/goji v1.0.1 h1:4lbD8Mx2h7IvloP7r2C0D6ltZP6Ufip8Hn0wmSK5LR8=
@@ -1022,9 +1101,15 @@ golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5D
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/exp/shiny v0.0.0-20230801115018-d63ba01acd4b h1:sgkbz1SFTsoQIvzTIw45hccUcGocu00QM3qucBYV8b0=
golang.org/x/exp/shiny v0.0.0-20230801115018-d63ba01acd4b/go.mod h1:UH99kUObWAZkDnWqppdQe5ZhPYESUw8I0zVV1uWBR+0=
golang.org/x/image v0.6.0 h1:bR8b5okrPI3g/gyZakLZHeWxAR8Dn5CyxXv1hLH5g/4=
golang.org/x/image v0.6.0/go.mod h1:MXLdDR43H7cDJq5GEGXEVeeNhPgi+YYEQ2pC1byI1x0=
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
@@ -1049,17 +1134,20 @@ golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457 h1:zf5N6UOrA487eEFacMePxjXAJctxKmyjKUsjA11Uzuk=
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
gonum.org/v1/plot v0.10.1 h1:dnifSs43YJuNMDzB7v8wV64O4ABBHReuAVAoBxqBqS4=
gonum.org/v1/plot v0.14.0 h1:+LBDVFYwFe4LHhdP8coW6296MBEY4nQ+Y4vuUpJopcE=
gonum.org/v1/plot v0.14.0/go.mod h1:MLdR9424SJed+5VqC6MsouEpig9pZX2VZ57H9ko2bXU=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/genproto v0.0.0-20240730163845-b1a4ccb954bf/go.mod h1:mCr1K1c8kX+1iSBREvU3Juo11CB+QOEWxbRS01wWl5M=
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU=
@@ -1075,8 +1163,10 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.
google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240730163845-b1a4ccb954bf/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/cheggaaa/pb.v1 v1.0.25 h1:Ev7yu1/f6+d+b3pi5vPdRPc6nNtP1umSfcWiEfRqv6I=
@@ -1107,13 +1197,14 @@ k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01 h1:pWEwq4Asjm4vjW7vcsmijwBhOr1/s
k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70 h1:NGrVE502P0s0/1hudf8zjgwki1X/TByhmAoILTarmzo=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo=
modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw=
modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q=
modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y=
modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw=
modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0=
modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/tcl v1.15.1 h1:mOQwiEK4p7HruMZcwKTZPw/aqtGM4aY00uzWhlKKYws=
modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE=
nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q=
+11 -10
View File
@@ -69,8 +69,8 @@
"releaseNotesUrl": "https://grafana.com/docs/grafana/next/release-notes/"
},
"devDependencies": {
"@babel/core": "7.25.7",
"@babel/preset-env": "7.25.7",
"@babel/core": "7.25.8",
"@babel/preset-env": "7.25.8",
"@babel/runtime": "7.25.7",
"@betterer/betterer": "5.4.0",
"@betterer/cli": "5.4.0",
@@ -84,10 +84,10 @@
"@manypkg/get-packages": "^2.2.0",
"@playwright/test": "1.48.0",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.15",
"@react-types/button": "3.9.6",
"@react-types/button": "3.10.0",
"@react-types/menu": "3.9.12",
"@react-types/overlays": "3.8.10",
"@react-types/shared": "3.24.1",
"@react-types/shared": "3.25.0",
"@rtk-query/codegen-openapi": "^1.2.0",
"@rtsao/plugin-proposal-class-properties": "7.0.1-patch.1",
"@swc/core": "1.4.2",
@@ -171,7 +171,7 @@
"cypress-recurse": "^1.35.3",
"esbuild": "0.24.0",
"esbuild-loader": "4.2.2",
"esbuild-plugin-browserslist": "^0.14.0",
"esbuild-plugin-browserslist": "^0.15.0",
"eslint": "8.57.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-import": "^2.26.0",
@@ -222,7 +222,7 @@
"redux-mock-store": "1.5.4",
"rimraf": "6.0.1",
"rudder-sdk-js": "2.48.19",
"sass": "1.79.3",
"sass": "1.79.4",
"sass-loader": "16.0.2",
"smtp-tester": "^2.1.0",
"style-loader": "4.0.0",
@@ -250,13 +250,13 @@
"@emotion/react": "11.13.3",
"@fingerprintjs/fingerprintjs": "^3.4.2",
"@floating-ui/react": "0.26.24",
"@formatjs/intl-durationformat": "^0.2.4",
"@formatjs/intl-durationformat": "^0.3.0",
"@glideapps/glide-data-grid": "^6.0.0",
"@grafana/aws-sdk": "0.5.0",
"@grafana/azure-sdk": "0.0.3",
"@grafana/data": "workspace:*",
"@grafana/e2e-selectors": "workspace:*",
"@grafana/experimental": "2.1.1",
"@grafana/experimental": "2.1.2",
"@grafana/faro-core": "^1.3.6",
"@grafana/faro-web-sdk": "^1.3.6",
"@grafana/faro-web-tracing": "^1.8.2",
@@ -268,11 +268,12 @@
"@grafana/prometheus": "workspace:*",
"@grafana/runtime": "workspace:*",
"@grafana/saga-icons": "workspace:*",
"@grafana/scenes": "5.18.3",
"@grafana/scenes": "5.20.0",
"@grafana/scenes-react": "5.20.0",
"@grafana/schema": "workspace:*",
"@grafana/sql": "workspace:*",
"@grafana/ui": "workspace:*",
"@hello-pangea/dnd": "16.6.0",
"@hello-pangea/dnd": "17.0.0",
"@kusto/monaco-kusto": "^10.0.0",
"@leeoniya/ufuzzy": "1.0.14",
"@lezer/common": "1.2.2",
@@ -198,7 +198,6 @@ export interface FeatureToggles {
zanzana?: boolean;
passScopeToDashboardApi?: boolean;
alertingApiServer?: boolean;
dashboardRestoreUI?: boolean;
cloudWatchRoundUpEndTime?: boolean;
cloudwatchMetricInsightsCrossAccount?: boolean;
prometheusAzureOverrideAudience?: boolean;
+4
View File
@@ -22,6 +22,7 @@ export const availableIconsIndex = {
'angle-up': true,
'align-left': true,
'align-right': true,
'api-endpoint': true,
'application-observability': true,
apps: true,
'archive-alt': true,
@@ -49,6 +50,7 @@ export const availableIconsIndex = {
bookmark: true,
'book-open': true,
'brackets-curly': true,
'browser-alt': true,
bug: true,
building: true,
'calculator-alt': true,
@@ -161,6 +163,7 @@ export const availableIconsIndex = {
info: true,
'info-circle': true,
k6: true,
'k6-rounded': true,
'key-skeleton-alt': true,
keyboard: true,
kubernetes: true,
@@ -184,6 +187,7 @@ export const availableIconsIndex = {
'minus-circle': true,
'mobile-android': true,
monitor: true,
'multi-step': true,
palette: true,
'panel-add': true,
paragraph: true,
+2 -2
View File
@@ -56,8 +56,8 @@
"tslib": "2.7.0"
},
"devDependencies": {
"@babel/core": "7.25.7",
"@babel/preset-env": "7.25.7",
"@babel/core": "7.25.8",
"@babel/preset-env": "7.25.8",
"@babel/preset-react": "7.25.7",
"@grafana/tsconfig": "^2.0.0",
"@rollup/plugin-node-resolve": "15.3.0",
+1 -1
View File
@@ -34,7 +34,7 @@
"build": "yarn generate && rollup -c rollup.config.ts --configPlugin esbuild"
},
"devDependencies": {
"@babel/core": "7.25.7",
"@babel/core": "7.25.8",
"@grafana/tsconfig": "^2.0.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.0",
@@ -20,7 +20,7 @@
"@emotion/css": "11.13.4",
"@grafana/data": "11.3.0-pre",
"@grafana/e2e-selectors": "11.3.0-pre",
"@grafana/experimental": "2.1.1",
"@grafana/experimental": "2.1.2",
"@grafana/runtime": "11.3.0-pre",
"@grafana/schema": "11.3.0-pre",
"@grafana/ui": "11.3.0-pre",
+3 -3
View File
@@ -39,12 +39,12 @@
"@emotion/css": "11.13.4",
"@floating-ui/react": "0.26.24",
"@grafana/data": "11.3.0-pre",
"@grafana/experimental": "2.1.1",
"@grafana/experimental": "2.1.2",
"@grafana/faro-web-sdk": "1.10.2",
"@grafana/runtime": "11.3.0-pre",
"@grafana/schema": "11.3.0-pre",
"@grafana/ui": "11.3.0-pre",
"@hello-pangea/dnd": "16.6.0",
"@hello-pangea/dnd": "17.0.0",
"@leeoniya/ufuzzy": "1.0.14",
"@lezer/common": "1.2.2",
"@lezer/highlight": "1.2.1",
@@ -131,7 +131,7 @@
"rollup-plugin-dts": "^6.1.1",
"rollup-plugin-esbuild": "6.1.1",
"rollup-plugin-node-externals": "^7.1.3",
"sass": "1.79.3",
"sass": "1.79.4",
"sass-loader": "16.0.2",
"style-loader": "4.0.0",
"testing-library-selector": "0.3.1",
@@ -112,5 +112,12 @@ describe('PromSettings', () => {
fireEvent.blur(input);
expect(queryByText(countError)).toBeInTheDocument();
});
it('should have a series endpoint configuration element', () => {
const options = defaultProps;
render(<PromSettings onOptionsChange={() => {}} options={options} />);
expect(screen.getByText('Use series endpoint')).toBeInTheDocument();
});
});
});
@@ -492,6 +492,26 @@ export const PromSettings = (props: Props) => {
</InlineField>
</div>
</div>
<InlineField
labelWidth={PROM_CONFIG_LABEL_WIDTH}
label="Use series endpoint"
tooltip={
<>
Checking this option will favor the series endpoint with match[] parameter over the label values
endpoint with match[] parameter. While the label values endpoint is considered more performant, some
users may prefer the series because it has a POST method while the label values endpoint only has a GET
method. {docsTip()}
</>
}
interactive={true}
disabled={options.readOnly}
className={styles.switchField}
>
<Switch
value={options.jsonData.seriesEndpoint ?? false}
onChange={onUpdateDatasourceJsonDataOptionChecked(props, 'seriesEndpoint')}
/>
</InlineField>
</div>
</ConfigSubSection>
@@ -111,6 +111,7 @@ export class PrometheusDatasource
cacheLevel: PrometheusCacheLevel;
cache: QueryCache<PromQuery>;
metricNamesAutocompleteSuggestionLimit: number;
seriesEndpoint: boolean;
constructor(
instanceSettings: DataSourceInstanceSettings<PromOptions>,
@@ -136,6 +137,7 @@ export class PrometheusDatasource
this.customQueryParameters = new URLSearchParams(instanceSettings.jsonData.customQueryParameters);
this.datasourceConfigurationPrometheusFlavor = instanceSettings.jsonData.prometheusType;
this.datasourceConfigurationPrometheusVersion = instanceSettings.jsonData.prometheusVersion;
this.seriesEndpoint = instanceSettings.jsonData.seriesEndpoint ?? false;
this.defaultEditor = instanceSettings.jsonData.defaultEditor;
this.disableRecordingRules = instanceSettings.jsonData.disableRecordingRules ?? false;
this.variables = new PrometheusVariableSupport(this, this.templateSrv);
@@ -183,6 +185,12 @@ export class PrometheusDatasource
}
hasLabelsMatchAPISupport(): boolean {
// users may choose the series endpoint as it has a POST method
// while the label values is only GET
if (this.seriesEndpoint) {
return false;
}
return (
// https://github.com/prometheus/prometheus/releases/tag/v2.24.0
this._isDatasourceVersionGreaterOrEqualTo('2.24.0', PromApplication.Prometheus) ||
+1
View File
@@ -53,6 +53,7 @@ export interface PromOptions extends DataSourceJsonData {
sigV4Auth?: boolean;
oauthPassThru?: boolean;
codeModeMetricNamesSuggestionLimit?: number;
seriesEndpoint?: boolean;
}
export type ExemplarTraceIdDestination = {
+1 -1
View File
@@ -17,7 +17,7 @@
"@emotion/css": "11.13.4",
"@grafana/data": "11.3.0-pre",
"@grafana/e2e-selectors": "11.3.0-pre",
"@grafana/experimental": "2.1.1",
"@grafana/experimental": "2.1.2",
"@grafana/runtime": "11.3.0-pre",
"@grafana/ui": "11.3.0-pre",
"@react-awesome-query-builder/ui": "6.6.3",
+2 -2
View File
@@ -55,7 +55,7 @@
"@grafana/e2e-selectors": "11.3.0-pre",
"@grafana/faro-web-sdk": "^1.3.6",
"@grafana/schema": "11.3.0-pre",
"@hello-pangea/dnd": "16.6.0",
"@hello-pangea/dnd": "17.0.0",
"@leeoniya/ufuzzy": "1.0.14",
"@monaco-editor/react": "4.6.0",
"@popperjs/core": "2.11.8",
@@ -115,7 +115,7 @@
"uuid": "9.0.1"
},
"devDependencies": {
"@babel/core": "7.25.7",
"@babel/core": "7.25.8",
"@faker-js/faker": "^9.0.0",
"@grafana/tsconfig": "^2.0.0",
"@rollup/plugin-node-resolve": "15.3.0",
@@ -15,6 +15,16 @@ jest.mock('../../utils/measureText', () => {
});
describe('AutoSizeInput', () => {
it('should support default Input API', () => {
const onChange = jest.fn();
render(<AutoSizeInput onChange={onChange} value="" />);
const input: HTMLInputElement = screen.getByTestId('autosize-input');
fireEvent.change(input, { target: { value: 'foo' } });
expect(onChange).toHaveBeenCalled();
});
it('should have default minWidth when empty', () => {
render(<AutoSizeInput />);
@@ -20,6 +20,7 @@ export const AutoSizeInput = React.forwardRef<HTMLInputElement, Props>((props, r
minWidth = 10,
maxWidth,
onCommitChange,
onChange,
onKeyDown,
onBlur,
value: controlledValue,
@@ -48,6 +49,9 @@ export const AutoSizeInput = React.forwardRef<HTMLInputElement, Props>((props, r
ref={ref}
value={value.toString()}
onChange={(event) => {
if (onChange) {
onChange(event);
}
setValue(event.currentTarget.value);
}}
width={inputWidth}
@@ -545,7 +545,8 @@ describe('Table utils', () => {
});
describe('guessLongestField', () => {
it('should guess the longest field correct if there are few records', () => {
// FLAKY TEST - https://drone.grafana.net/grafana/grafana/201232/1/5
it.skip('should guess the longest field correct if there are few records', () => {
const data = getWrappableData(10);
const config = {
defaults: {
+12 -12
View File
@@ -23,7 +23,7 @@ require (
require (
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/NYTimes/gziphandler v1.1.1 // indirect
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/apache/arrow/go/v15 v15.0.2 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
@@ -53,7 +53,7 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/cel-go v0.20.1 // indirect
github.com/google/cel-go v0.21.0 // indirect
github.com/google/flatbuffers v24.3.25+incompatible // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
@@ -98,7 +98,7 @@ require (
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.20.3 // indirect
github.com/prometheus/client_golang v1.20.4 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
@@ -118,21 +118,21 @@ require (
go.etcd.io/etcd/api/v3 v3.5.14 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect
go.etcd.io/etcd/client/v3 v3.5.14 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.55.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 // indirect
go.opentelemetry.io/contrib/propagators/jaeger v1.30.0 // indirect
go.opentelemetry.io/contrib/samplers/jaegerremote v0.23.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 // indirect
go.opentelemetry.io/otel/metric v1.30.0 // indirect
go.opentelemetry.io/otel/sdk v1.29.0 // indirect
go.opentelemetry.io/otel/sdk v1.30.0 // indirect
go.opentelemetry.io/otel/trace v1.30.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect
golang.org/x/mod v0.20.0 // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect
@@ -143,11 +143,11 @@ require (
golang.org/x/time v0.6.0 // indirect
golang.org/x/tools v0.24.0 // indirect
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
gonum.org/v1/gonum v0.14.0 // indirect
gonum.org/v1/gonum v0.15.1 // indirect
google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/grpc v1.66.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/grpc v1.67.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
+24 -24
View File
@@ -5,8 +5,8 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
github.com/apache/arrow/go/v15 v15.0.2 h1:60IliRbiyTWCWjERBCkO1W4Qun9svcYoZrSLcyOsMLE=
github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
@@ -106,8 +106,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84=
github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg=
github.com/google/cel-go v0.21.0 h1:cl6uW/gxN+Hy50tNYvI691+sXxioCnstFzLp2WO4GCI=
github.com/google/cel-go v0.21.0/go.mod h1:rHUlWCcBKgyEk+eV03RPdZUekPp6YcJwV0FxuUksYxc=
github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI=
github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
@@ -247,8 +247,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4=
github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI=
github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@@ -342,8 +342,8 @@ go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA=
go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw=
go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok=
go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 h1:hCq2hNMwsegUvPzI7sPOvtO9cqyy5GbWt/Ybp2xrx8Q=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0/go.mod h1:LqaApwGx/oUmzsbqxkzuBvyoPpkxk3JQWnqfVrJ3wCA=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.55.0 h1:sqmsIQ75l6lfZjjpnXXT9DFVtYEDg6CH0/Cn4/3A1Wg=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.55.0/go.mod h1:rsg1EO8LXSs2po50PB5CeY/MSVlhghuKBgXlKnqm6ks=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs=
@@ -355,16 +355,16 @@ go.opentelemetry.io/contrib/samplers/jaegerremote v0.23.0/go.mod h1:1kbAgQa5lgYC
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts=
go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 h1:lsInsfvhVIfOI6qHVyysXMNDnjO9Npvl7tlDPJFBVd4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0/go.mod h1:KQsVNh4OjgjTG0G6EiNi1jVpnaeeKsKMRwbLN+f1+8M=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 h1:m0yTiGDLUvVYaTFbAvCkVYIYcvwKt3G7OLoN77NUs/8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0/go.mod h1:wBQbT4UekBfegL2nx0Xk1vBcnzyBPsIVm9hRG4fYcr4=
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w=
go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ=
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo=
go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE=
go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc=
go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o=
@@ -386,8 +386,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -462,8 +462,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk=
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU=
gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0=
gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@@ -471,18 +471,18 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 h1:CT2Thj5AuPV9phrYMtzX11k+XkzMGfRAet42PmoTATM=
google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988/go.mod h1:7uvplUBj4RjHAxIZ//98LzOvrQ04JBkaixRmCMI29hc=
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo=
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc=
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw=
google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+36 -59
View File
@@ -20,6 +20,7 @@ import (
"github.com/grafana/grafana/pkg/api/routing"
folderalpha1 "github.com/grafana/grafana/pkg/apis/folder/v0alpha1"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/infra/slugify"
internalfolders "github.com/grafana/grafana/pkg/registry/apis/folders"
"github.com/grafana/grafana/pkg/services/accesscontrol"
grafanaapiserver "github.com/grafana/grafana/pkg/services/apiserver"
@@ -635,8 +636,6 @@ type folderK8sHandler struct {
// #TODO check if it makes more sense to move this to FolderAPIBuilder
accesscontrolService accesscontrol.Service
userService user.Service
// #TODO remove after we handle the nested folder case
folderService folder.Service
}
//-----------------------------------------------------------------------------------------
@@ -650,7 +649,6 @@ func newFolderK8sHandler(hs *HTTPServer) *folderK8sHandler {
clientConfigProvider: hs.clientConfigProvider,
accesscontrolService: hs.accesscontrolService,
userService: hs.userService,
folderService: hs.folderService,
}
}
@@ -884,55 +882,38 @@ func (fk8s *folderK8sHandler) newToFolderDto(c *contextmodel.ReqContext, item un
return dtos.Folder{}, err
}
parents := []*folder.Folder{}
if folderDTO.ParentUID != "" {
parents, err = fk8s.folderService.GetParents(
c.Req.Context(),
folder.GetParentsQuery{
UID: folderDTO.UID,
OrgID: folderDTO.OrgID,
})
if err != nil {
return dtos.Folder{}, err
}
if len(f.Fullpath) == 0 || len(f.FullpathUIDs) == 0 {
return folderDTO, nil
}
// #TODO refactor so that we have just one function for converting to folder DTO
toParentDTO := func(fold *folder.Folder, checkCanView bool) (dtos.Folder, error) {
g, err := guardian.NewByFolder(c.Req.Context(), fold, c.SignedInUser.GetOrgID(), c.SignedInUser)
if err != nil {
return dtos.Folder{}, err
}
parentsFullPath, err := internalfolders.GetParentTitles(f.Fullpath)
if err != nil {
return dtos.Folder{}, err
}
parentsFullPathUIDs := strings.Split(f.FullpathUIDs, "/")
if checkCanView {
canView, _ := g.CanView()
if !canView {
return dtos.Folder{
UID: REDACTED,
Title: REDACTED,
}, nil
}
}
metrics.MFolderIDsAPICount.WithLabelValues(metrics.NewToFolderDTO).Inc()
return dtos.Folder{
UID: fold.UID,
Title: fold.Title,
URL: fold.URL,
}, nil
// The first part of the path is the newly created folder which we don't need to include
// in the parents field
if len(parentsFullPath) < 2 || len(parentsFullPathUIDs) < 2 {
return folderDTO, nil
}
folderDTO.Parents = make([]dtos.Folder, 0, len(parents))
for _, f := range parents {
DTO, err := toParentDTO(f, true)
if err != nil {
// #TODO add logging
// fk8s.log.Error("failed to convert folder to DTO", "folder", f.UID, "org", f.OrgID, "error", err)
continue
}
folderDTO.Parents = append(folderDTO.Parents, DTO)
parents := []dtos.Folder{}
for i, v := range parentsFullPath[1:] {
slug := slugify.Slugify(v)
uid := parentsFullPathUIDs[1:][i]
url := dashboards.GetFolderURL(uid, slug)
parents = append(parents, dtos.Folder{
UID: uid,
OrgID: c.SignedInUser.GetOrgID(),
Title: v,
URL: url,
})
}
folderDTO.Parents = parents
return folderDTO, nil
}
@@ -953,23 +934,19 @@ func (fk8s *folderK8sHandler) getFolderACMetadata(c *contextmodel.ReqContext, f
return nil, nil
}
var err error
parents := []*folder.Folder{}
if f.ParentUID != "" {
parents, err = fk8s.folderService.GetParents(
c.Req.Context(),
folder.GetParentsQuery{
UID: f.UID,
OrgID: c.SignedInUser.GetOrgID(),
})
if err != nil {
return nil, err
}
if len(f.FullpathUIDs) == 0 {
return map[string]bool{}, nil
}
parentsFullPathUIDs := strings.Split(f.FullpathUIDs, "/")
// The first part of the path is the newly created folder which we don't need to check here
if len(parentsFullPathUIDs) < 2 {
return map[string]bool{}, nil
}
folderIDs := map[string]bool{f.UID: true}
for _, p := range parents {
folderIDs[p.UID] = true
for _, uid := range parentsFullPathUIDs[1:] {
folderIDs[uid] = true
}
allMetadata := getMultiAccessControlMetadata(c, dashboards.ScopeFoldersPrefix, folderIDs)
+2 -2
View File
@@ -39,8 +39,8 @@ require (
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.18.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/grpc v1.66.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/grpc v1.67.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
+4 -4
View File
@@ -135,10 +135,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw=
google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+26
View File
@@ -34,6 +34,11 @@ const AnnoKeyOriginPath = "grafana.app/originPath"
const AnnoKeyOriginHash = "grafana.app/originHash"
const AnnoKeyOriginTimestamp = "grafana.app/originTimestamp"
// #TODO revisit keeping these folder-specific annotations once we have complete support for mode 1
const AnnoKeyFullPath = "grafana.app/fullPath"
const AnnoKeyFullPathUIDs = "grafana.app/fullPathUIDs"
// ResourceOriginInfo is saved in annotations. This is used to identify where the resource came from
// This object can model the same data as our existing provisioning table or a more general git sync
type ResourceOriginInfo struct {
@@ -101,6 +106,11 @@ type GrafanaMetaAccessor interface {
// NOTE the type must match the existing value, or an error will be thrown
SetStatus(any) error
GetFullPath() string
SetFullPath(path string)
GetFullPathUIDs() string
SetFullPathUIDs(path string)
// Find a title in the object
// This will reflect the object and try to get:
// * spec.title
@@ -598,6 +608,22 @@ func (m *grafanaMetaAccessor) SetStatus(s any) (err error) {
return
}
func (m *grafanaMetaAccessor) GetFullPath() string {
return m.get(AnnoKeyFullPath)
}
func (m *grafanaMetaAccessor) SetFullPath(path string) {
m.SetAnnotation(AnnoKeyFullPath, path)
}
func (m *grafanaMetaAccessor) GetFullPathUIDs() string {
return m.get(AnnoKeyFullPathUIDs)
}
func (m *grafanaMetaAccessor) SetFullPathUIDs(path string) {
m.SetAnnotation(AnnoKeyFullPathUIDs, path)
}
func (m *grafanaMetaAccessor) FindTitle(defaultTitle string) string {
// look for Spec.Title or Spec.Name
spec := m.r.FieldByName("Spec")
+9
View File
@@ -1,6 +1,8 @@
package v0alpha1
import (
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -15,6 +17,13 @@ type Team struct {
type TeamSpec struct {
Title string `json:"title,omitempty"`
Email string `json:"email,omitempty"`
// This is currently used for authorization checks but we don't want to expose it
InternalID int64 `json:"-"`
}
func (t Team) AuthID() string {
return fmt.Sprintf("%d", t.Spec.InternalID)
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+9 -9
View File
@@ -6,7 +6,7 @@ require (
github.com/google/go-cmp v0.6.0
github.com/grafana/authlib/claims v0.0.0-20240903121118-16441568af1e
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240701135906-559738ce6ae1
github.com/prometheus/client_golang v1.20.3
github.com/prometheus/client_golang v1.20.4
github.com/stretchr/testify v1.9.0
go.opentelemetry.io/contrib/propagators/jaeger v1.30.0
go.opentelemetry.io/otel v1.30.0
@@ -64,16 +64,16 @@ require (
go.etcd.io/etcd/api/v3 v3.5.14 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect
go.etcd.io/etcd/client/v3 v3.5.14 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 // indirect
go.opentelemetry.io/otel/metric v1.30.0 // indirect
go.opentelemetry.io/otel/sdk v1.29.0 // indirect
go.opentelemetry.io/otel/sdk v1.30.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sys v0.25.0 // indirect
@@ -82,9 +82,9 @@ require (
golang.org/x/time v0.6.0 // indirect
golang.org/x/tools v0.24.0 // indirect
google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/grpc v1.66.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/grpc v1.67.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
+18 -18
View File
@@ -132,8 +132,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4=
github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI=
github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@@ -188,22 +188,22 @@ go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA=
go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw=
go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok=
go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 h1:hCq2hNMwsegUvPzI7sPOvtO9cqyy5GbWt/Ybp2xrx8Q=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0/go.mod h1:LqaApwGx/oUmzsbqxkzuBvyoPpkxk3JQWnqfVrJ3wCA=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI=
go.opentelemetry.io/contrib/propagators/jaeger v1.30.0 h1:g8+Y+7lnhH1DB0THjPPthzQ+RlzAntmTz8+TH2sRU0k=
go.opentelemetry.io/contrib/propagators/jaeger v1.30.0/go.mod h1:lRMaD/FjOQJ2yz/MwOHYxP/BTCMFodNW/wuYDkJvdA4=
go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts=
go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 h1:lsInsfvhVIfOI6qHVyysXMNDnjO9Npvl7tlDPJFBVd4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0/go.mod h1:KQsVNh4OjgjTG0G6EiNi1jVpnaeeKsKMRwbLN+f1+8M=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 h1:m0yTiGDLUvVYaTFbAvCkVYIYcvwKt3G7OLoN77NUs/8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0/go.mod h1:wBQbT4UekBfegL2nx0Xk1vBcnzyBPsIVm9hRG4fYcr4=
go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w=
go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ=
go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo=
go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE=
go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg=
go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc=
go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
@@ -224,8 +224,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -290,18 +290,18 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 h1:CT2Thj5AuPV9phrYMtzX11k+XkzMGfRAet42PmoTATM=
google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988/go.mod h1:7uvplUBj4RjHAxIZ//98LzOvrQ04JBkaixRmCMI29hc=
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo=
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc=
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw=
google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+9 -9
View File
@@ -20,7 +20,7 @@ require (
github.com/Masterminds/semver/v3 v3.2.0 // @grafana/grafana-release-guild
github.com/aws/aws-sdk-go v1.55.5 // @grafana/aws-datasources
github.com/blang/semver/v4 v4.0.0 // @grafana/grafana-release-guild
github.com/docker/docker v26.0.2+incompatible // @grafana/grafana-release-guild
github.com/docker/docker v27.3.1+incompatible // @grafana/grafana-release-guild
github.com/drone/drone-cli v1.6.1 // @grafana/grafana-release-guild
github.com/gogo/protobuf v1.3.2 // indirect; @grafana/alerting-backend
github.com/google/go-cmp v0.6.0 // @grafana/grafana-backend-group
@@ -32,9 +32,9 @@ require (
github.com/stretchr/testify v1.9.0 // @grafana/grafana-backend-group
github.com/urfave/cli v1.22.15 // @grafana/grafana-backend-group
github.com/urfave/cli/v2 v2.27.1 // @grafana/grafana-backend-group
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect; @grafana/plugins-platform-backend
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 // indirect; @grafana/plugins-platform-backend
go.opentelemetry.io/otel v1.30.0 // indirect; @grafana/grafana-backend-group
go.opentelemetry.io/otel/sdk v1.29.0 // indirect; @grafana/grafana-backend-group
go.opentelemetry.io/otel/sdk v1.30.0 // indirect; @grafana/grafana-backend-group
go.opentelemetry.io/otel/trace v1.30.0 // indirect; @grafana/grafana-backend-group
golang.org/x/crypto v0.27.0 // indirect; @grafana/grafana-backend-group
golang.org/x/mod v0.20.0 // @grafana/grafana-backend-group
@@ -45,7 +45,7 @@ require (
golang.org/x/time v0.6.0 // indirect; @grafana/grafana-backend-group
golang.org/x/tools v0.24.0 // indirect; @grafana/grafana-as-code
google.golang.org/api v0.191.0 // @grafana/grafana-backend-group
google.golang.org/grpc v1.66.0 // indirect; @grafana/plugins-platform-backend
google.golang.org/grpc v1.67.0 // indirect; @grafana/plugins-platform-backend
google.golang.org/protobuf v1.34.2 // indirect; @grafana/plugins-platform-backend
gopkg.in/yaml.v3 v3.0.1 // @grafana/alerting-backend
)
@@ -87,8 +87,8 @@ require (
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
golang.org/x/sys v0.25.0 // indirect
google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 // indirect; @grafana/grafana-backend-group
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
@@ -110,13 +110,13 @@ require (
github.com/vektah/gqlparser/v2 v2.5.11 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240518090000-14441aefdf88 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.2.0-alpha // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 // indirect
go.opentelemetry.io/otel/log v0.2.0-alpha // indirect
go.opentelemetry.io/otel/sdk/log v0.2.0-alpha // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect
gotest.tools/v3 v3.5.1 // indirect
)
+16 -16
View File
@@ -227,8 +227,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 h1:hCq2hNMwsegUvPzI7sPOvtO9cqyy5GbWt/Ybp2xrx8Q=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0/go.mod h1:LqaApwGx/oUmzsbqxkzuBvyoPpkxk3JQWnqfVrJ3wCA=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI=
go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts=
@@ -237,18 +237,18 @@ go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-2024051809000
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240518090000-14441aefdf88/go.mod h1:JGG8ebaMO5nXOPnvKEl+DiA4MGwFjCbjsxT1WHIEBPY=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.2.0-alpha h1:z2s6Zba+OUyayRv5m1AXWNUTGh57K1iMhy6emU5QT5Y=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.2.0-alpha/go.mod h1:paOXXyUgPW6jYxYkP0pB47H2zHE1fPvMJ4E4G9LHOi0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 h1:lsInsfvhVIfOI6qHVyysXMNDnjO9Npvl7tlDPJFBVd4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0/go.mod h1:KQsVNh4OjgjTG0G6EiNi1jVpnaeeKsKMRwbLN+f1+8M=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 h1:m0yTiGDLUvVYaTFbAvCkVYIYcvwKt3G7OLoN77NUs/8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0/go.mod h1:wBQbT4UekBfegL2nx0Xk1vBcnzyBPsIVm9hRG4fYcr4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 h1:JAv0Jwtl01UFiyWZEMiJZBiTlv5A50zNs8lsthXqIio=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0/go.mod h1:QNKLmUEAq2QUbPQUfvw4fmv0bgbK7UlOSFCnXyfvSNc=
go.opentelemetry.io/otel/log v0.2.0-alpha h1:ixOPvMzserpqA07SENHvRzkZOsnG0XbPr74hv1AQ+n0=
go.opentelemetry.io/otel/log v0.2.0-alpha/go.mod h1:vbFZc65yq4c4ssvXY43y/nIqkNJLxORrqw0L85P59LA=
go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w=
go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ=
go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo=
go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE=
go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg=
go.opentelemetry.io/otel/sdk/log v0.2.0-alpha h1:jGTkL/jroJ31jnP6jDl34N/mDOfRGGYZHcHsCM+5kWA=
go.opentelemetry.io/otel/sdk/log v0.2.0-alpha/go.mod h1:Hd8Lw9FPGUM3pfY7iGMRvFaC2Nyau4Ajb5WnQ9OdIho=
go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc=
@@ -266,8 +266,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -339,18 +339,18 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 h1:CT2Thj5AuPV9phrYMtzX11k+XkzMGfRAet42PmoTATM=
google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988/go.mod h1:7uvplUBj4RjHAxIZ//98LzOvrQ04JBkaixRmCMI29hc=
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo=
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc=
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw=
google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+2 -1
View File
@@ -3,7 +3,8 @@ package backendplugin
import (
"github.com/grafana/grafana/pkg/plugins/log"
"go.opentelemetry.io/otel/trace"
)
// PluginFactoryFunc is a function type for creating a Plugin.
type PluginFactoryFunc func(pluginID string, logger log.Logger, env func() []string) (Plugin, error)
type PluginFactoryFunc func(pluginID string, logger log.Logger, tracer trace.Tracer, env func() []string) (Plugin, error)
@@ -4,6 +4,7 @@ import (
"context"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"go.opentelemetry.io/otel/trace"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/backendplugin"
@@ -24,7 +25,7 @@ type corePlugin struct {
// New returns a new backendplugin.PluginFactoryFunc for creating a core (built-in) backendplugin.Plugin.
func New(opts backend.ServeOpts) backendplugin.PluginFactoryFunc {
return func(pluginID string, logger log.Logger, _ func() []string) (backendplugin.Plugin, error) {
return func(pluginID string, logger log.Logger, _ trace.Tracer, _ func() []string) (backendplugin.Plugin, error) {
return &corePlugin{
pluginID: pluginID,
logger: logger,
@@ -8,13 +8,14 @@ import (
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
"github.com/grafana/grafana/pkg/plugins/log"
"github.com/grafana/grafana/pkg/plugins/manager/fakes"
"github.com/stretchr/testify/require"
)
func TestCorePlugin(t *testing.T) {
t.Run("New core plugin with empty opts should return expected values", func(t *testing.T) {
factory := coreplugin.New(backend.ServeOpts{})
p, err := factory("plugin", log.New("test"), nil)
p, err := factory("plugin", log.New("test"), fakes.InitializeNoopTracerForTest(), nil)
require.NoError(t, err)
require.NotNil(t, p)
require.NoError(t, p.Start(context.Background()))
@@ -47,7 +48,7 @@ func TestCorePlugin(t *testing.T) {
return nil
}),
})
p, err := factory("plugin", log.New("test"), nil)
p, err := factory("plugin", log.New("test"), fakes.InitializeNoopTracerForTest(), nil)
require.NoError(t, err)
require.NotNil(t, p)
require.NoError(t, p.Start(context.Background()))
@@ -254,7 +254,7 @@ func NewPlugin(pluginID string, cfg *setting.Cfg, httpClientProvider *httpclient
if backendFactory == nil {
return nil, ErrCorePluginNotFound
}
bp, err := backendFactory(p.ID, p.Logger(), nil)
bp, err := backendFactory(p.ID, p.Logger(), tracer, nil)
if err != nil {
return nil, err
}
+23 -2
View File
@@ -6,6 +6,8 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/grpcplugin"
goplugin "github.com/hashicorp/go-plugin"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
trace "go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/embedded"
"google.golang.org/grpc"
"github.com/grafana/grafana/pkg/plugins/backendplugin"
@@ -40,7 +42,20 @@ var pluginSet = map[int]goplugin.PluginSet{
},
}
func newClientConfig(executablePath string, args []string, env []string, skipHostEnvVars bool, logger log.Logger,
type clientTracerProvider struct {
tracer trace.Tracer
embedded.TracerProvider
}
func (ctp *clientTracerProvider) Tracer(instrumentationName string, opts ...trace.TracerOption) trace.Tracer {
return ctp.tracer
}
func newClientTracerProvider(tracer trace.Tracer) trace.TracerProvider {
return &clientTracerProvider{tracer: tracer}
}
func newClientConfig(executablePath string, args []string, env []string, skipHostEnvVars bool, logger log.Logger, tracer trace.Tracer,
versionedPlugins map[int]goplugin.PluginSet) *goplugin.ClientConfig {
// We can ignore gosec G201 here, since the dynamic part of executablePath comes from the plugin definition
// nolint:gosec
@@ -55,7 +70,13 @@ func newClientConfig(executablePath string, args []string, env []string, skipHos
Logger: logWrapper{Logger: logger},
AllowedProtocols: []goplugin.Protocol{goplugin.ProtocolGRPC},
GRPCDialOptions: []grpc.DialOption{
grpc.WithStatsHandler(otelgrpc.NewClientHandler()),
// https://github.com/grafana/app-platform-wg/issues/140
// external plugins are loaded before k8s API server
// configures the tracing service thus failing to
// record trace span in the middleware.
// With code below we are passing the same tracer that k8s API server
// uses so that middleware is configured with tracer.
grpc.WithStatsHandler(otelgrpc.NewClientHandler(otelgrpc.WithTracerProvider(newClientTracerProvider(tracer)))),
},
}
}
@@ -4,6 +4,7 @@ import (
"context"
"errors"
trace "go.opentelemetry.io/otel/trace"
"google.golang.org/grpc"
"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2"
@@ -44,6 +45,7 @@ type ProtoClientOpts struct {
ExecutableArgs []string
Env []string
Logger log.Logger
Tracer trace.Tracer
}
func NewProtoClient(opts ProtoClientOpts) (ProtoClient, error) {
@@ -56,6 +58,7 @@ func NewProtoClient(opts ProtoClientOpts) (ProtoClient, error) {
versionedPlugins: pluginSet,
},
opts.Logger,
opts.Tracer,
func() []string { return opts.Env },
)
@@ -7,6 +7,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/hashicorp/go-plugin"
trace "go.opentelemetry.io/otel/trace"
"github.com/grafana/grafana/pkg/infra/process"
"github.com/grafana/grafana/pkg/plugins"
@@ -37,17 +38,17 @@ const (
// newPlugin allocates and returns a new gRPC (external) backendplugin.Plugin.
func newPlugin(descriptor PluginDescriptor) backendplugin.PluginFactoryFunc {
return func(pluginID string, logger log.Logger, env func() []string) (backendplugin.Plugin, error) {
return newGrpcPlugin(descriptor, logger, env), nil
return func(pluginID string, logger log.Logger, tracer trace.Tracer, env func() []string) (backendplugin.Plugin, error) {
return newGrpcPlugin(descriptor, logger, tracer, env), nil
}
}
func newGrpcPlugin(descriptor PluginDescriptor, logger log.Logger, env func() []string) *grpcPlugin {
func newGrpcPlugin(descriptor PluginDescriptor, logger log.Logger, tracer trace.Tracer, env func() []string) *grpcPlugin {
return &grpcPlugin{
descriptor: descriptor,
logger: logger,
clientFactory: func() *plugin.Client {
return plugin.NewClient(newClientConfig(descriptor.executablePath, descriptor.executableArgs, env(), descriptor.skipHostEnvVars, logger, descriptor.versionedPlugins))
return plugin.NewClient(newClientConfig(descriptor.executablePath, descriptor.executableArgs, env(), descriptor.skipHostEnvVars, logger, tracer, descriptor.versionedPlugins))
},
state: pluginStateNotStarted,
}
+11 -1
View File
@@ -8,6 +8,8 @@ import (
"sync"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/noop"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/auth"
@@ -267,6 +269,14 @@ func (r *FakePluginRepo) PluginVersion(ctx context.Context, pluginID, version st
return repo.VersionData{}, nil
}
type fakeTracerProvider struct {
noop.TracerProvider
}
func InitializeNoopTracerForTest() trace.Tracer {
return fakeTracerProvider{}.Tracer("test")
}
type FakePluginStorage struct {
ExtractFunc func(_ context.Context, pluginID string, dirNameFunc storage.DirNameGeneratorFunc, z *zip.ReadCloser) (*storage.ExtractedPluginArchive, error)
}
@@ -340,7 +350,7 @@ func NewFakeBackendProcessProvider() *FakeBackendProcessProvider {
}
f.BackendFactoryFunc = func(ctx context.Context, p *plugins.Plugin) backendplugin.PluginFactoryFunc {
f.Requested[p.ID]++
return func(pluginID string, _ log.Logger, _ func() []string) (backendplugin.Plugin, error) {
return func(pluginID string, _ log.Logger, _ trace.Tracer, _ func() []string) (backendplugin.Plugin, error) {
f.Invoked[pluginID]++
return &FakePluginClient{}, nil
}
@@ -9,6 +9,7 @@ import (
"github.com/grafana/grafana/pkg/plugins/log"
"github.com/grafana/grafana/pkg/plugins/manager/process"
"github.com/grafana/grafana/pkg/plugins/manager/registry"
"go.opentelemetry.io/otel/trace"
)
// BackendClientInit implements an InitializeFunc for initializing a backend plugin process.
@@ -21,20 +22,22 @@ type BackendClientInit struct {
envVarProvider envvars.Provider
backendProvider plugins.BackendFactoryProvider
log log.Logger
tracer trace.Tracer
}
// BackendClientInitStep returns a new InitializeFunc for registering a backend plugin process.
func BackendClientInitStep(envVarProvider envvars.Provider,
backendProvider plugins.BackendFactoryProvider) InitializeFunc {
return newBackendProcessRegistration(envVarProvider, backendProvider).Initialize
backendProvider plugins.BackendFactoryProvider, tracer trace.Tracer) InitializeFunc {
return newBackendProcessRegistration(envVarProvider, backendProvider, tracer).Initialize
}
func newBackendProcessRegistration(envVarProvider envvars.Provider,
backendProvider plugins.BackendFactoryProvider) *BackendClientInit {
backendProvider plugins.BackendFactoryProvider, tracer trace.Tracer) *BackendClientInit {
return &BackendClientInit{
backendProvider: backendProvider,
envVarProvider: envVarProvider,
log: log.New("plugins.backend.registration"),
tracer: tracer,
}
}
@@ -49,7 +52,7 @@ func (b *BackendClientInit) Initialize(ctx context.Context, p *plugins.Plugin) (
// this will ensure that the env variables are calculated every time a plugin is started
envFunc := func() []string { return b.envVarProvider.PluginEnvVars(ctx, p) }
if backendClient, err := backendFactory(p.ID, p.Logger(), envFunc); err != nil {
if backendClient, err := backendFactory(p.ID, p.Logger(), b.tracer, envFunc); err != nil {
return nil, err
} else {
p.RegisterClient(backendClient)
@@ -4,11 +4,12 @@ import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/backendplugin"
"github.com/grafana/grafana/pkg/plugins/log"
"github.com/grafana/grafana/pkg/plugins/manager/fakes"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/trace"
)
func TestInitializer_Initialize(t *testing.T) {
@@ -28,7 +29,7 @@ func TestInitializer_Initialize(t *testing.T) {
Class: plugins.ClassCore,
}
stepFunc := BackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{plugin: p})
stepFunc := BackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{plugin: p}, fakes.InitializeNoopTracerForTest())
var err error
p, err = stepFunc(context.Background(), p)
@@ -52,7 +53,7 @@ func TestInitializer_Initialize(t *testing.T) {
Class: plugins.ClassExternal,
}
stepFunc := BackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{plugin: p})
stepFunc := BackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{plugin: p}, fakes.InitializeNoopTracerForTest())
var err error
p, err = stepFunc(context.Background(), p)
@@ -76,7 +77,7 @@ func TestInitializer_Initialize(t *testing.T) {
Class: plugins.ClassExternal,
}
stepFunc := BackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{plugin: p})
stepFunc := BackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{plugin: p}, fakes.InitializeNoopTracerForTest())
var err error
p, err = stepFunc(context.Background(), p)
@@ -96,7 +97,7 @@ func TestInitializer_Initialize(t *testing.T) {
i := BackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{
plugin: p,
})
}, fakes.InitializeNoopTracerForTest())
var err error
p, err = i(context.Background(), p)
@@ -115,7 +116,7 @@ type fakeBackendProvider struct {
}
func (f *fakeBackendProvider) BackendFactory(_ context.Context, _ *plugins.Plugin) backendplugin.PluginFactoryFunc {
return func(_ string, _ log.Logger, _ func() []string) (backendplugin.Plugin, error) {
return func(_ string, _ log.Logger, _ trace.Tracer, _ func() []string) (backendplugin.Plugin, error) {
return f.plugin, nil
}
}
+10 -10
View File
@@ -7,13 +7,13 @@ require (
github.com/grafana/grafana-plugin-sdk-go v0.251.0
github.com/json-iterator/go v1.1.12
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/prometheus/client_golang v1.20.3
github.com/prometheus/client_golang v1.20.4
github.com/prometheus/common v0.55.0
github.com/prometheus/prometheus v1.8.2-0.20221021121301-51a44e6657c3
github.com/stretchr/testify v1.9.0
go.opentelemetry.io/otel v1.30.0
go.opentelemetry.io/otel/trace v1.30.0
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e
k8s.io/apimachinery v0.31.1
)
@@ -101,14 +101,14 @@ require (
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.55.0 // indirect
go.opentelemetry.io/contrib/propagators/jaeger v1.30.0 // indirect
go.opentelemetry.io/contrib/samplers/jaegerremote v0.23.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 // indirect
go.opentelemetry.io/otel/metric v1.30.0 // indirect
go.opentelemetry.io/otel/sdk v1.29.0 // indirect
go.opentelemetry.io/otel/sdk v1.30.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/goleak v1.3.0 // indirect
@@ -119,10 +119,10 @@ require (
golang.org/x/text v0.18.0 // indirect
golang.org/x/tools v0.24.0 // indirect
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
gonum.org/v1/gonum v0.14.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/grpc v1.66.0 // indirect
gonum.org/v1/gonum v0.15.1 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/grpc v1.67.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
+20 -20
View File
@@ -199,8 +199,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4=
github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI=
github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
@@ -262,8 +262,8 @@ github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 h1:hCq2hNMwsegUvPzI7sPOvtO9cqyy5GbWt/Ybp2xrx8Q=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0/go.mod h1:LqaApwGx/oUmzsbqxkzuBvyoPpkxk3JQWnqfVrJ3wCA=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.55.0 h1:sqmsIQ75l6lfZjjpnXXT9DFVtYEDg6CH0/Cn4/3A1Wg=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.55.0/go.mod h1:rsg1EO8LXSs2po50PB5CeY/MSVlhghuKBgXlKnqm6ks=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs=
@@ -275,16 +275,16 @@ go.opentelemetry.io/contrib/samplers/jaegerremote v0.23.0/go.mod h1:1kbAgQa5lgYC
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts=
go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 h1:lsInsfvhVIfOI6qHVyysXMNDnjO9Npvl7tlDPJFBVd4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0/go.mod h1:KQsVNh4OjgjTG0G6EiNi1jVpnaeeKsKMRwbLN+f1+8M=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 h1:m0yTiGDLUvVYaTFbAvCkVYIYcvwKt3G7OLoN77NUs/8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0/go.mod h1:wBQbT4UekBfegL2nx0Xk1vBcnzyBPsIVm9hRG4fYcr4=
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w=
go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ=
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo=
go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE=
go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc=
go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o=
@@ -297,8 +297,8 @@ go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
@@ -349,14 +349,14 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk=
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU=
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo=
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0=
gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o=
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc=
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw=
google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+32 -4
View File
@@ -2,6 +2,7 @@ package folders
import (
"fmt"
"regexp"
"strconv"
"time"
@@ -85,10 +86,12 @@ func UnstructuredToLegacyFolder(item unstructured.Unstructured, orgID int64) *fo
// #TODO add created by field if necessary
// CreatedBy: meta.GetCreatedBy(),
// UpdatedBy: meta.GetCreatedBy(),
URL: getURL(meta, title),
Created: createdTime,
Updated: createdTime,
OrgID: orgID,
URL: getURL(meta, title),
Created: createdTime,
Updated: createdTime,
OrgID: orgID,
Fullpath: meta.GetFullPath(),
FullpathUIDs: meta.GetFullPathUIDs(),
}
return f
}
@@ -183,6 +186,12 @@ func convertToK8sResource(v *folder.Folder, namespacer request.NamespaceMapper)
if v.ParentUID != "" {
meta.SetFolder(v.ParentUID)
}
if v.Fullpath != "" {
meta.SetFullPath(v.Fullpath)
}
if v.FullpathUIDs != "" {
meta.SetFullPathUIDs(v.FullpathUIDs)
}
f.UID = gapiutil.CalculateClusterWideUID(f)
return f, nil
}
@@ -226,3 +235,22 @@ func getCreated(meta utils.GrafanaMetaAccessor) (*time.Time, error) {
}
return created, nil
}
func GetParentTitles(fullPath string) ([]string, error) {
// Find all forward slashes which aren't escaped
r, err := regexp.Compile(`[^\\](/)`)
if err != nil {
return nil, err
}
indices := r.FindAllStringIndex(fullPath, -1)
var start int
titles := []string{}
for _, i := range indices {
titles = append(titles, fullPath[start:i[0]+1])
start = i[0] + 2
}
titles = append(titles, fullPath[start:])
return titles, nil
}
@@ -0,0 +1,18 @@
package folders
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestGetParentTitles(t *testing.T) {
path := "get\\/folder-folder-0/get\\/folder-folder-1/another"
titles, err := GetParentTitles(path)
require.Nil(t, err)
require.Equal(t, 3, len(titles))
require.Equal(t, "get\\/folder-folder-0", titles[0])
require.Equal(t, "get\\/folder-folder-1", titles[1])
require.Equal(t, "another", titles[2])
}
+13
View File
@@ -54,6 +54,19 @@ func newLegacyAuthorizer(ac accesscontrol.AccessControl, store legacy.LegacyIden
return []string{fmt.Sprintf("serviceaccounts:id:%d", res.ID)}, nil
}),
},
accesscontrol.ResourceAuthorizerOptions{
Resource: iamv0.TeamResourceInfo.GetName(),
Attr: "id",
Resolver: accesscontrol.ResourceResolverFunc(func(ctx context.Context, ns claims.NamespaceInfo, name string) ([]string, error) {
res, err := store.GetTeamInternalID(ctx, ns, legacy.GetTeamInternalIDQuery{
UID: name,
})
if err != nil {
return nil, err
}
return []string{fmt.Sprintf("teams:id:%d", res.ID)}, nil
}),
},
)
return gfauthorizer.NewResourceAuthorizer(client), client
+1
View File
@@ -22,6 +22,7 @@ type LegacyIdentityStore interface {
ListServiceAccounts(ctx context.Context, ns claims.NamespaceInfo, query ListServiceAccountsQuery) (*ListServiceAccountResult, error)
ListServiceAccountTokens(ctx context.Context, ns claims.NamespaceInfo, query ListServiceAccountTokenQuery) (*ListServiceAccountTokenResult, error)
GetTeamInternalID(ctx context.Context, ns claims.NamespaceInfo, query GetTeamInternalIDQuery) (*GetTeamInternalIDResult, error)
ListTeams(ctx context.Context, ns claims.NamespaceInfo, query ListTeamQuery) (*ListTeamResult, error)
ListTeamBindings(ctx context.Context, ns claims.NamespaceInfo, query ListTeamBindingsQuery) (*ListTeamBindingsResult, error)
ListTeamMembers(ctx context.Context, ns claims.NamespaceInfo, query ListTeamMembersQuery) (*ListTeamMembersResult, error)
+74
View File
@@ -3,6 +3,7 @@ package legacy
import (
"context"
"database/sql"
"errors"
"fmt"
"time"
@@ -14,6 +15,79 @@ import (
"github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate"
)
type GetTeamInternalIDQuery struct {
OrgID int64
UID string
}
type GetTeamInternalIDResult struct {
ID int64
}
var sqlQueryTeamInternalIDTemplate = mustTemplate("team_internal_id.sql")
func newGetTeamInternalID(sql *legacysql.LegacyDatabaseHelper, q *GetTeamInternalIDQuery) getTeamInternalIDQuery {
return getTeamInternalIDQuery{
SQLTemplate: sqltemplate.New(sql.DialectForDriver()),
TeamTable: sql.Table("team"),
Query: q,
}
}
type getTeamInternalIDQuery struct {
sqltemplate.SQLTemplate
TeamTable string
Query *GetTeamInternalIDQuery
}
func (r getTeamInternalIDQuery) Validate() error { return nil }
func (s *legacySQLStore) GetTeamInternalID(
ctx context.Context,
ns claims.NamespaceInfo,
query GetTeamInternalIDQuery,
) (*GetTeamInternalIDResult, error) {
query.OrgID = ns.OrgID
if query.OrgID == 0 {
return nil, fmt.Errorf("expected non zero org id")
}
sql, err := s.sql(ctx)
if err != nil {
return nil, err
}
req := newGetTeamInternalID(sql, &query)
q, err := sqltemplate.Execute(sqlQueryTeamInternalIDTemplate, req)
if err != nil {
return nil, fmt.Errorf("execute template %q: %w", sqlQueryTeamInternalIDTemplate.Name(), err)
}
rows, err := sql.DB.GetSqlxSession().Query(ctx, q, req.GetArgs()...)
defer func() {
if rows != nil {
_ = rows.Close()
}
}()
if err != nil {
return nil, err
}
if !rows.Next() {
return nil, errors.New("team not found")
}
var id int64
if err := rows.Scan(&id); err != nil {
return nil, err
}
return &GetTeamInternalIDResult{
id,
}, nil
}
type ListTeamQuery struct {
OrgID int64
UID string
@@ -0,0 +1,5 @@
SELECT t.id
FROM {{ .Ident .TeamTable }} as t
WHERE t.org_id = {{ .Arg .Query.OrgID }}
AND t.uid = {{ .Arg .Query.UID }}
LIMIT 1;
+1 -1
View File
@@ -97,7 +97,7 @@ func (b *IdentityAccessManagementAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *ge
storage := map[string]rest.Storage{}
teamResource := iamv0.TeamResourceInfo
storage[teamResource.StoragePath()] = team.NewLegacyStore(b.store)
storage[teamResource.StoragePath()] = team.NewLegacyStore(b.store, b.accessClient)
storage[teamResource.StoragePath("members")] = team.NewLegacyTeamMemberREST(b.store)
teamBindingResource := iamv0.TeamBindingResourceInfo
+67 -54
View File
@@ -2,6 +2,7 @@ package team
import (
"context"
"fmt"
"strconv"
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
@@ -15,6 +16,7 @@ import (
"github.com/grafana/grafana/pkg/registry/apis/iam/common"
"github.com/grafana/grafana/pkg/registry/apis/iam/legacy"
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
"github.com/grafana/grafana/pkg/services/team"
)
var (
@@ -27,12 +29,13 @@ var (
var resource = iamv0.TeamResourceInfo
func NewLegacyStore(store legacy.LegacyIdentityStore) *LegacyStore {
return &LegacyStore{store}
func NewLegacyStore(store legacy.LegacyIdentityStore, ac claims.AccessClient) *LegacyStore {
return &LegacyStore{store, ac}
}
type LegacyStore struct {
store legacy.LegacyIdentityStore
ac claims.AccessClient
}
func (s *LegacyStore) New() runtime.Object {
@@ -58,74 +61,84 @@ func (s *LegacyStore) ConvertToTable(ctx context.Context, object runtime.Object,
return resource.TableConverter().ConvertToTable(ctx, object, tableOptions)
}
func (s *LegacyStore) doList(ctx context.Context, ns claims.NamespaceInfo, query legacy.ListTeamQuery) (*iamv0.TeamList, error) {
rsp, err := s.store.ListTeams(ctx, ns, query)
if err != nil {
return nil, err
}
list := &iamv0.TeamList{
ListMeta: metav1.ListMeta{
ResourceVersion: strconv.FormatInt(rsp.RV, 10),
func (s *LegacyStore) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) {
res, err := common.List(
ctx, resource.GetName(), s.ac, common.PaginationFromListOptions(options),
func(ctx context.Context, ns claims.NamespaceInfo, p common.Pagination) (*common.ListResponse[iamv0.Team], error) {
found, err := s.store.ListTeams(ctx, ns, legacy.ListTeamQuery{
Pagination: p,
})
if err != nil {
return nil, err
}
teams := make([]iamv0.Team, 0, len(found.Teams))
for _, t := range found.Teams {
teams = append(teams, toTeamObject(t, ns))
}
return &common.ListResponse[iamv0.Team]{
Items: teams,
RV: found.RV,
Continue: found.Continue,
}, nil
},
}
for _, team := range rsp.Teams {
item := iamv0.Team{
ObjectMeta: metav1.ObjectMeta{
Name: team.UID,
Namespace: ns.Value,
CreationTimestamp: metav1.NewTime(team.Created),
ResourceVersion: strconv.FormatInt(team.Updated.UnixMilli(), 10),
},
Spec: iamv0.TeamSpec{
Title: team.Name,
Email: team.Email,
},
}
meta, err := utils.MetaAccessor(&item)
if err != nil {
return nil, err
}
meta.SetUpdatedTimestamp(&team.Updated)
meta.SetOriginInfo(&utils.ResourceOriginInfo{
Name: "SQL",
Path: strconv.FormatInt(team.ID, 10),
})
list.Items = append(list.Items, item)
)
if err != nil {
return nil, fmt.Errorf("failed to list teams: %w", err)
}
list.ListMeta.Continue = common.OptionalFormatInt(rsp.Continue)
list.ListMeta.ResourceVersion = common.OptionalFormatInt(rsp.RV)
list := &iamv0.TeamList{Items: res.Items}
list.ListMeta.Continue = common.OptionalFormatInt(res.Continue)
list.ListMeta.ResourceVersion = common.OptionalFormatInt(res.RV)
return list, nil
}
func (s *LegacyStore) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) {
ns, err := request.NamespaceInfoFrom(ctx, true)
if err != nil {
return nil, err
}
return s.doList(ctx, ns, legacy.ListTeamQuery{
OrgID: ns.OrgID,
Pagination: common.PaginationFromListOptions(options),
})
}
func (s *LegacyStore) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
ns, err := request.NamespaceInfoFrom(ctx, true)
if err != nil {
return nil, err
}
rsp, err := s.doList(ctx, ns, legacy.ListTeamQuery{
found, err := s.store.ListTeams(ctx, ns, legacy.ListTeamQuery{
OrgID: ns.OrgID,
UID: name,
Pagination: common.Pagination{Limit: 1},
})
if err != nil {
return nil, err
if found == nil || err != nil {
return nil, resource.NewNotFound(name)
}
if len(rsp.Items) > 0 {
return &rsp.Items[0], nil
if len(found.Teams) < 1 {
return nil, resource.NewNotFound(name)
}
return nil, resource.NewNotFound(name)
obj := toTeamObject(found.Teams[0], ns)
return &obj, nil
}
func toTeamObject(t team.Team, ns claims.NamespaceInfo) iamv0.Team {
obj := iamv0.Team{
ObjectMeta: metav1.ObjectMeta{
Name: t.UID,
Namespace: ns.Value,
CreationTimestamp: metav1.NewTime(t.Created),
ResourceVersion: strconv.FormatInt(t.Updated.UnixMilli(), 10),
},
Spec: iamv0.TeamSpec{
Title: t.Name,
Email: t.Email,
InternalID: t.ID,
},
}
meta, _ := utils.MetaAccessor(&obj)
meta.SetUpdatedTimestamp(&t.Updated)
meta.SetOriginInfo(&utils.ResourceOriginInfo{
Name: "SQL",
Path: strconv.FormatInt(t.ID, 10),
})
return obj
}
+13 -6
View File
@@ -122,15 +122,22 @@ func (r *queryREST) Connect(connectCtx context.Context, name string, _ runtime.O
// Parses the request and splits it into multiple sub queries (if necessary)
req, err := b.parser.parseRequest(ctx, raw)
if err != nil {
reason := metav1.StatusReasonInvalid
message := err.Error()
if errors.Is(err, datasources.ErrDataSourceNotFound) {
reason = metav1.StatusReasonNotFound
// TODO, can we wrap the error somehow?
err = &errorsK8s.StatusError{ErrStatus: metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusBadRequest, // the URL is found, but includes bad requests
Reason: metav1.StatusReasonNotFound,
Message: "datasource not found",
}}
message = "datasource not found"
}
err = &errorsK8s.StatusError{ErrStatus: metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusBadRequest,
Reason: reason,
Message: message,
}}
responder.Error(err)
return
}
+57 -10
View File
@@ -3,7 +3,12 @@ package search
import (
"encoding/json"
"net/http"
"net/url"
"strconv"
"github.com/grafana/grafana/pkg/api/response"
request2 "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
"github.com/grafana/grafana/pkg/setting"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/authorization/authorizer"
@@ -21,14 +26,17 @@ import (
var _ builder.APIGroupBuilder = (*SearchAPIBuilder)(nil)
type SearchAPIBuilder struct {
unified resource.ResourceClient
unified resource.ResourceClient
namespacer request2.NamespaceMapper
}
func NewSearchAPIBuilder(
unified resource.ResourceClient,
cfg *setting.Cfg,
) (*SearchAPIBuilder, error) {
return &SearchAPIBuilder{
unified: unified,
unified: unified,
namespacer: request2.GetNamespaceMapper(cfg),
}, nil
}
@@ -36,11 +44,12 @@ func RegisterAPIService(
features featuremgmt.FeatureToggles,
apiregistration builder.APIRegistrar,
unified resource.ResourceClient,
cfg *setting.Cfg,
) (*SearchAPIBuilder, error) {
if !(features.IsEnabledGlobally(featuremgmt.FlagUnifiedStorageSearch) || features.IsEnabledGlobally(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs)) {
return nil, nil
}
builder, err := NewSearchAPIBuilder(unified)
builder, err := NewSearchAPIBuilder(unified, cfg)
apiregistration.RegisterAPI(builder)
return builder, err
}
@@ -73,17 +82,55 @@ func (b *SearchAPIBuilder) GetAPIRoutes() *builder.APIRoutes {
},
},
},
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
urlQuery := r.URL.Query().Get("query")
searchRequest := &resource.SearchRequest{Query: urlQuery}
Handler: func(w http.ResponseWriter, r *http.Request) {
// get tenant
orgId, err := request2.OrgIDForList(r.Context())
if err != nil {
response.Error(500, "failed to get orgId", err)
}
tenant := b.namespacer(orgId)
queryParams, err := url.ParseQuery(r.URL.RawQuery)
if err != nil {
response.Error(500, "failed to parse query params", err)
}
// get limit and offset from query params
limit := 0
offset := 0
if queryParams.Has("limit") {
limit, _ = strconv.Atoi(queryParams.Get("limit"))
}
if queryParams.Has("offset") {
offset, _ = strconv.Atoi(queryParams.Get("offset"))
}
searchRequest := &resource.SearchRequest{
Tenant: tenant,
Kind: queryParams.Get("kind"),
QueryType: queryParams.Get("queryType"),
Query: queryParams.Get("query"),
Limit: int64(limit),
Offset: int64(offset),
}
res, err := b.unified.Search(r.Context(), searchRequest)
if err != nil {
panic(err)
response.Error(500, "search request failed", err)
}
if err := json.NewEncoder(w).Encode(res); err != nil {
panic(err)
// TODO need a nicer way of handling this
// the [][]byte response already contains the marshalled JSON, so we don't need to re-encode it
rawMessages := make([]json.RawMessage, len(res.GetItems()))
for i, item := range res.GetItems() {
rawMessages[i] = item.Value
}
}),
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(rawMessages); err != nil {
response.Error(500, "failed to json encode raw response", err)
}
},
},
},
}
@@ -3,12 +3,15 @@ package acimpl
import (
"context"
"errors"
"strconv"
"time"
openfgav1 "github.com/openfga/api/proto/openfga/v1"
"github.com/prometheus/client_golang/prometheus"
"go.opentelemetry.io/otel"
"github.com/grafana/authlib/claims"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/metrics"
@@ -127,6 +130,7 @@ func (a *AccessControl) evaluateZanzana(ctx context.Context, user identity.Reque
a.log.Debug("evaluating zanzana", "user", tupleKey.User, "relation", tupleKey.Relation, "object", tupleKey.Object)
allowed, err := a.Check(ctx, accesscontrol.CheckRequest{
// Namespace: claims.OrgNamespaceFormatter(user.GetOrgID()),
User: tupleKey.User,
Relation: tupleKey.Relation,
Object: tupleKey.Object,
@@ -226,12 +230,44 @@ func (a *AccessControl) Check(ctx context.Context, req accesscontrol.CheckReques
Relation: req.Relation,
Object: req.Object,
}
in := &openfgav1.CheckRequest{TupleKey: key}
in := &openfgav1.CheckRequest{
TupleKey: key,
}
// Check direct access to resource first
res, err := a.zclient.Check(ctx, in)
if err != nil {
return false, err
}
return res.Allowed, err
// no need to check folder access
if res.Allowed || req.Parent == "" {
return res.Allowed, nil
}
// Check access through the parent folder
ns, err := claims.ParseNamespace(req.Namespace)
if err != nil {
return false, err
}
folderKey := &openfgav1.CheckRequestTupleKey{
User: req.User,
Relation: zanzana.TranslateToFolderRelation(req.Relation, req.ObjectType),
Object: zanzana.NewScopedTupleEntry(zanzana.TypeFolder, req.Parent, "", strconv.FormatInt(ns.OrgID, 10)),
}
folderReq := &openfgav1.CheckRequest{
TupleKey: folderKey,
}
folderRes, err := a.zclient.Check(ctx, folderReq)
if err != nil {
return false, err
}
return folderRes.Allowed, nil
}
func (a *AccessControl) ListObjects(ctx context.Context, req accesscontrol.ListObjectsRequest) ([]string, error) {
+1 -42
View File
@@ -39,7 +39,6 @@ func NewZanzanaSynchroniser(client zanzana.Client, store db.DB, collectors ...Tu
teamMembershipCollector(store),
managedPermissionsCollector(store),
folderTreeCollector(store),
dashboardFolderCollector(store),
basicRolesCollector(store),
customRolesCollector(store),
basicRoleAssignemtCollector(store),
@@ -58,6 +57,7 @@ func NewZanzanaSynchroniser(client zanzana.Client, store db.DB, collectors ...Tu
// Sync runs all collectors and tries to write all collected tuples.
// It will skip over any "sync group" that has already been written.
func (z *ZanzanaSynchroniser) Sync(ctx context.Context) error {
z.log.Info("Starting zanzana permissions sync")
ctx, span := tracer.Start(ctx, "accesscontrol.migrator.Sync")
defer span.End()
@@ -246,47 +246,6 @@ func folderTreeCollector(store db.DB) TupleCollector {
}
}
// dashboardFolderCollector collects information about dashboards parent folders
func dashboardFolderCollector(store db.DB) TupleCollector {
return func(ctx context.Context, tuples map[string][]*openfgav1.TupleKey) error {
ctx, span := tracer.Start(ctx, "accesscontrol.migrator.dashboardFolderCollector")
defer span.End()
const collectorID = "folder"
query := `
SELECT org_id, uid, folder_uid, is_folder FROM dashboard
WHERE is_folder = ` + store.GetDialect().BooleanStr(false) + `
AND folder_uid IS NOT NULL
`
type dashboard struct {
OrgID int64 `xorm:"org_id"`
UID string `xorm:"uid"`
ParentUID string `xorm:"folder_uid"`
}
var dashboards []dashboard
err := store.WithDbSession(ctx, func(sess *db.Session) error {
return sess.SQL(query).Find(&dashboards)
})
if err != nil {
return err
}
for _, d := range dashboards {
tuple := &openfgav1.TupleKey{
User: zanzana.NewScopedTupleEntry(zanzana.TypeFolder, d.ParentUID, "", strconv.FormatInt(d.OrgID, 10)),
Object: zanzana.NewScopedTupleEntry(zanzana.TypeDashboard, d.UID, "", strconv.FormatInt(d.OrgID, 10)),
Relation: zanzana.RelationParent,
}
tuples[collectorID] = append(tuples[collectorID], tuple)
}
return nil
}
}
// basicRolesCollector migrates basic roles to OpenFGA tuples
func basicRolesCollector(store db.DB) TupleCollector {
return func(ctx context.Context, tuples map[string][]*openfgav1.TupleKey) error {
+6 -3
View File
@@ -589,9 +589,12 @@ type QueryWithOrg struct {
}
type CheckRequest struct {
User string
Relation string
Object string
Namespace string
User string
Relation string
Object string
ObjectType string
Parent string
}
type ListObjectsRequest struct {
+10 -3
View File
@@ -4,12 +4,15 @@ import (
"log/slog"
"strconv"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/log/slogadapter"
"github.com/spf13/pflag"
genericfeatures "k8s.io/apiserver/pkg/features"
genericapiserver "k8s.io/apiserver/pkg/server"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/component-base/logs"
"k8s.io/klog/v2"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/log/slogadapter"
)
type ExtraOptions struct {
@@ -40,7 +43,11 @@ func (o *ExtraOptions) Validate() []error {
func (o *ExtraOptions) ApplyTo(c *genericapiserver.RecommendedConfig) error {
handler := slogadapter.New(log.New("grafana-apiserver"))
logger := slog.New(handler)
if err := utilfeature.DefaultMutableFeatureGate.SetFromMap(map[string]bool{
string(genericfeatures.APIServerTracing): false,
}); err != nil {
return err
}
klog.SetSlogLogger(logger)
if _, err := logs.GlogSetter(strconv.Itoa(o.Verbosity)); err != nil {
logger.Error("failed to set log level", "error", err)
+18 -10
View File
@@ -491,7 +491,7 @@ func orgIDFromHeader(req *http.Request) int64 {
}
func (s *Service) resolveExternalSessionFromIdentity(ctx context.Context, identity *authn.Identity, userID int64) *auth.ExternalSession {
if identity.OAuthToken == nil {
if identity.OAuthToken == nil && identity.SAMLSession == nil {
return nil
}
@@ -506,18 +506,26 @@ func (s *Service) resolveExternalSessionFromIdentity(ctx context.Context, identi
UserAuthID: info.Id,
UserID: userID,
}
extSession.AccessToken = identity.OAuthToken.AccessToken
extSession.RefreshToken = identity.OAuthToken.RefreshToken
extSession.ExpiresAt = identity.OAuthToken.Expiry
if idToken, ok := identity.OAuthToken.Extra("id_token").(string); ok && idToken != "" {
extSession.IDToken = idToken
if identity.OAuthToken != nil {
extSession.AccessToken = identity.OAuthToken.AccessToken
extSession.RefreshToken = identity.OAuthToken.RefreshToken
extSession.ExpiresAt = identity.OAuthToken.Expiry
if idToken, ok := identity.OAuthToken.Extra("id_token").(string); ok && idToken != "" {
extSession.IDToken = idToken
}
// As of https://openid.net/specs/openid-connect-session-1_0.html
if sessionState, ok := identity.OAuthToken.Extra("session_state").(string); ok && sessionState != "" {
extSession.SessionID = sessionState
}
return extSession
}
// As of https://openid.net/specs/openid-connect-session-1_0.html
if sessionState, ok := identity.OAuthToken.Extra("session_state").(string); ok && sessionState != "" {
extSession.SessionID = sessionState
}
extSession.SessionID = identity.SAMLSession.SessionIndex
extSession.NameID = identity.SAMLSession.NameID
return extSession
}
@@ -87,18 +87,25 @@ func (s *OrgSync) SyncOrgRolesHook(ctx context.Context, id *authn.Identity, _ *a
orgIDs := make([]int64, 0, len(id.OrgRoles))
// add any new org roles
for orgId, orgRole := range id.OrgRoles {
orgIDs = append(orgIDs, orgId)
if _, exists := handledOrgIds[orgId]; exists {
orgIDs = append(orgIDs, orgId)
continue
}
// add role
cmd := &org.AddOrgUserCommand{UserID: userID, Role: orgRole, OrgID: orgId}
err := s.orgService.AddOrgUser(ctx, cmd)
if err != nil && !errors.Is(err, org.ErrOrgNotFound) {
if errors.Is(err, org.ErrOrgNotFound) {
continue
}
if err != nil {
ctxLogger.Error("Failed to update active org for user", "error", err)
return err
}
orgIDs = append(orgIDs, orgId)
}
// delete any removed org roles
@@ -24,7 +24,8 @@ import (
)
func TestOrgSync_SyncOrgRolesHook(t *testing.T) {
orgService := &orgtest.FakeOrgService{ExpectedUserOrgDTO: []*org.UserOrgDTO{
orgService := &orgtest.MockService{}
orgService.On("GetUserOrgList", mock.Anything, mock.Anything).Return([]*org.UserOrgDTO{
{
OrgID: 1,
Role: org.RoleEditor,
@@ -33,14 +34,16 @@ func TestOrgSync_SyncOrgRolesHook(t *testing.T) {
OrgID: 3,
Role: org.RoleViewer,
},
},
ExpectedOrgListResponse: orgtest.OrgListResponse{
{
OrgID: 3,
Response: nil,
},
},
}
}, nil)
orgService.On("RemoveOrgUser", mock.Anything, mock.MatchedBy(func(cmd *org.RemoveOrgUserCommand) bool {
return cmd.OrgID == 3 && cmd.UserID == 1
})).Return(nil)
orgService.On("UpdateOrgUser", mock.Anything, mock.MatchedBy(func(cmd *org.UpdateOrgUserCommand) bool {
return cmd.OrgID == 1 && cmd.UserID == 1 && cmd.Role == org.RoleAdmin
})).Return(nil)
orgService.On("AddOrgUser", mock.Anything, mock.MatchedBy(func(cmd *org.AddOrgUserCommand) bool {
return cmd.OrgID == 2 && cmd.UserID == 1 && cmd.Role == org.RoleEditor
})).Return(org.ErrOrgNotFound)
acService := &actest.FakeService{}
userService := &usertest.FakeUserService{ExpectedUser: &user.User{
ID: 1,
@@ -67,7 +70,7 @@ func TestOrgSync_SyncOrgRolesHook(t *testing.T) {
wantID *authn.Identity
}{
{
name: "add user to multiple orgs",
name: "add user to multiple orgs, should not set the user's default orgID to an org that does not exist",
fields: fields{
userService: userService,
orgService: orgService,
@@ -100,7 +103,7 @@ func TestOrgSync_SyncOrgRolesHook(t *testing.T) {
Name: "test",
Email: "test",
OrgRoles: map[int64]identity.RoleType{1: org.RoleAdmin, 2: org.RoleEditor},
OrgID: 1, //set using org
OrgID: 1, // set using org
IsGrafanaAdmin: ptrBool(false),
ClientParams: authn.ClientParams{
SyncOrgRoles: true,
+1 -1
View File
@@ -185,10 +185,10 @@ func (s *ExtendedJWT) authenticateAsService(accessTokenClaims authlib.Claims[aut
return &authn.Identity{
ID: id,
UID: id,
Name: id,
Type: t,
OrgID: s.cfg.DefaultOrgID(),
AccessTokenClaims: &accessTokenClaims,
IDTokenClaims: nil,
AuthenticatedBy: login.ExtendedJWTModule,
AuthID: accessTokenClaims.Subject,
AllowedKubernetesNamespace: accessTokenClaims.Rest.Namespace,
@@ -228,6 +228,7 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
want: &authn.Identity{
ID: "this-uid",
UID: "this-uid",
Name: "this-uid",
Type: claims.TypeAccessPolicy,
OrgID: 1,
AccessTokenClaims: &validAccessTokenClaims,
@@ -246,6 +247,7 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
want: &authn.Identity{
ID: "this-uid",
UID: "this-uid",
Name: "this-uid",
Type: claims.TypeAccessPolicy,
OrgID: 1,
AccessTokenClaims: &validAccessTokenClaimsWildcard,
@@ -343,6 +345,7 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
want: &authn.Identity{
ID: "this-uid",
UID: "this-uid",
Name: "this-uid",
Type: claims.TypeAccessPolicy,
OrgID: 1,
AccessTokenClaims: &validAccessTokenClaimsWithStackSet,
@@ -369,6 +372,7 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
want: &authn.Identity{
ID: "this-uid",
UID: "this-uid",
Name: "this-uid",
Type: claims.TypeAccessPolicy,
OrgID: 1,
AccessTokenClaims: &validAccessTokenClaimsWithDeprecatedStackClaimSet,
+2
View File
@@ -64,6 +64,8 @@ type Identity struct {
Groups []string
// OAuthToken is the OAuth token used to authenticate the entity.
OAuthToken *oauth2.Token
// SAMLSession is the SAML session information.
SAMLSession *login.SAMLSession
// SessionToken is the session token used to authenticate the entity.
SessionToken *usertoken.UserToken
// ClientParams are hints for the auth service on how to handle the identity.
@@ -4,10 +4,14 @@ import (
"context"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/openfga/openfga/pkg/logger"
)
var _ logger.Logger = (*ZanzanaLogger)(nil)
// ZanzanaLogger is a grafana logger wrapper compatible with OpenFGA logger interface
type ZanzanaLogger struct {
logger log.Logger
@@ -36,6 +40,13 @@ func zapFieldsToArgs(fields []zap.Field) []any {
return args
}
// With implements logger.Logger.
func (l *ZanzanaLogger) With(fields ...zapcore.Field) logger.Logger {
return &ZanzanaLogger{
logger: l.logger.New(zapFieldsToArgs(fields)...),
}
}
func (l *ZanzanaLogger) Debug(msg string, fields ...zap.Field) {
l.logger.Debug(msg, zapFieldsToArgs(fields)...)
}
+11 -12
View File
@@ -28,18 +28,17 @@ extend type org
type dashboard
relations
define org: [org]
define parent: [folder]
define read: [user, team#member, role#assignee] or dashboard_read from parent or dashboard_read from org
define write: [user, team#member, role#assignee] or dashboard_write from parent or dashboard_write from org
define delete: [user, team#member, role#assignee] or dashboard_delete from parent or dashboard_delete from org
define create: [user, team#member, role#assignee] or dashboard_create from parent or dashboard_create from org
define permissions_read: [user, team#member, role#assignee] or dashboard_permissions_read from parent or dashboard_permissions_read from org
define permissions_write: [user, team#member, role#assignee] or dashboard_permissions_write from parent or dashboard_permissions_write from org
define read: [user, team#member, role#assignee] or dashboard_read from org
define write: [user, team#member, role#assignee] or dashboard_write from org
define delete: [user, team#member, role#assignee] or dashboard_delete from org
define create: [user, team#member, role#assignee] or dashboard_create from org
define permissions_read: [user, team#member, role#assignee] or dashboard_permissions_read from org
define permissions_write: [user, team#member, role#assignee] or dashboard_permissions_write from org
define public_write: [user, team#member, role#assignee] or dashboard_public_write from parent or dashboard_public_write from org or write
define annotations_create: [user, team#member, role#assignee] or dashboard_annotations_create from parent or dashboard_annotations_create from org
define annotations_read: [user, team#member, role#assignee] or dashboard_annotations_read from parent or dashboard_annotations_read from org
define annotations_write: [user, team#member, role#assignee] or dashboard_annotations_write from parent or dashboard_annotations_write from org
define annotations_delete: [user, team#member, role#assignee] or dashboard_annotations_delete from parent or dashboard_annotations_delete from org
define public_write: [user, team#member, role#assignee] or dashboard_public_write from org or write
define annotations_create: [user, team#member, role#assignee] or dashboard_annotations_create from org
define annotations_read: [user, team#member, role#assignee] or dashboard_annotations_read from org
define annotations_write: [user, team#member, role#assignee] or dashboard_annotations_write from org
define annotations_delete: [user, team#member, role#assignee] or dashboard_annotations_delete from org
@@ -1,10 +0,0 @@
package assets
import "embed"
// EmbedMigrations within the grafana binary.
//
//go:embed migrations/*
var EmbedMigrations embed.FS
const SQLiteMigrationDir = "migrations/sqlite"
@@ -1,56 +0,0 @@
-- +goose Up
CREATE TABLE tuple (
store CHAR(26) NOT NULL,
object_type VARCHAR(128) NOT NULL,
object_id VARCHAR(128) NOT NULL,
relation VARCHAR(50) NOT NULL,
_user VARCHAR(256) NOT NULL,
user_type VARCHAR(7) NOT NULL,
ulid CHAR(26) NOT NULL,
inserted_at TIMESTAMP NOT NULL,
PRIMARY KEY (store, object_type, object_id, relation, _user)
);
CREATE UNIQUE INDEX idx_tuple_ulid ON tuple (ulid);
CREATE TABLE authorization_model (
store CHAR(26) NOT NULL,
authorization_model_id CHAR(26) NOT NULL,
type VARCHAR(256) NOT NULL,
type_definition BLOB,
PRIMARY KEY (store, authorization_model_id, type)
);
CREATE TABLE store (
id CHAR(26) PRIMARY KEY,
name VARCHAR(64) NOT NULL,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP,
deleted_at TIMESTAMP
);
CREATE TABLE assertion (
store CHAR(26) NOT NULL,
authorization_model_id CHAR(26) NOT NULL,
assertions BLOB,
PRIMARY KEY (store, authorization_model_id)
);
CREATE TABLE changelog (
store CHAR(26) NOT NULL,
object_type VARCHAR(256) NOT NULL,
object_id VARCHAR(256) NOT NULL,
relation VARCHAR(50) NOT NULL,
_user VARCHAR(512) NOT NULL,
operation INTEGER NOT NULL,
ulid CHAR(26) NOT NULL,
inserted_at TIMESTAMP NOT NULL,
PRIMARY KEY (store, ulid, object_type)
);
-- +goose Down
DROP TABLE tuple;
DROP TABLE authorization_model;
DROP TABLE store;
DROP TABLE assertion;
DROP TABLE changelog;
@@ -1,5 +0,0 @@
-- +goose Up
ALTER TABLE authorization_model ADD COLUMN schema_version VARCHAR(5) NOT NULL DEFAULT '1.0';
-- +goose Down
ALTER TABLE authorization_model DROP COLUMN schema_version;
@@ -1,5 +0,0 @@
-- +goose Up
CREATE INDEX idx_reverse_lookup_user on tuple (store, object_type, relation, _user);
-- +goose Down
DROP INDEX idx_reverse_lookup_user on tuple;
@@ -1,5 +0,0 @@
-- +goose Up
ALTER TABLE authorization_model ADD COLUMN serialized_protobuf LONGBLOB;
-- +goose Down
ALTER TABLE authorization_model DROP COLUMN serialized_protobuf;
@@ -1,11 +0,0 @@
-- +goose Up
ALTER TABLE tuple ADD COLUMN condition_name VARCHAR(256);
ALTER TABLE tuple ADD COLUMN condition_context LONGBLOB;
ALTER TABLE changelog ADD COLUMN condition_name VARCHAR(256);
ALTER TABLE changelog ADD COLUMN condition_context LONGBLOB;
-- +goose Down
ALTER TABLE tuple DROP COLUMN condition_name;
ALTER TABLE tuple DROP COLUMN condition_context;
ALTER TABLE changelog DROP COLUMN condition_name;
ALTER TABLE changelog DROP COLUMN condition_context;
@@ -15,13 +15,17 @@ import (
func Run(cfg *setting.Cfg, typ, connStr string, fs embed.FS, path string) error {
engine, err := xorm.NewEngine(typ, connStr)
if err != nil {
return fmt.Errorf("failed to parse database config: %w", err)
return fmt.Errorf("failed to create db engine: %w", err)
}
m := migrator.NewMigrator(engine, cfg)
m.AddCreateMigration()
return RunWithMigrator(m, cfg, fs, path)
if err := RunWithMigrator(m, cfg, fs, path); err != nil {
return err
}
return engine.Close()
}
func RunWithMigrator(m *migrator.Migrator, cfg *setting.Cfg, fs embed.FS, path string) error {
@@ -1,15 +0,0 @@
package sqlite
import "github.com/openfga/openfga/pkg/storage/sqlcommon"
type Config struct {
*sqlcommon.Config
QueryRetries int
}
func NewConfig() *Config {
return &Config{
Config: sqlcommon.NewConfig(),
QueryRetries: 0,
}
}
@@ -1,821 +0,0 @@
package sqlite
import (
"context"
"database/sql"
"encoding/json"
"errors"
"fmt"
"net/url"
"strings"
"time"
sq "github.com/Masterminds/squirrel"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
"go.opentelemetry.io/otel"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/timestamppb"
// Pull in sqlite driver.
"github.com/mattn/go-sqlite3"
openfgav1 "github.com/openfga/api/proto/openfga/v1"
"github.com/openfga/openfga/pkg/logger"
"github.com/openfga/openfga/pkg/storage"
"github.com/openfga/openfga/pkg/storage/sqlcommon"
tupleUtils "github.com/openfga/openfga/pkg/tuple"
)
var tracer = otel.Tracer("openfga/pkg/storage/sqlite")
// SQLite provides a SQLite based implementation of [storage.OpenFGADatastore].
type SQLite struct {
stbl sq.StatementBuilderType
cfg *Config
db *sql.DB
dbInfo *sqlcommon.DBInfo
sqlTime sq.Sqlizer
logger logger.Logger
dbStatsCollector prometheus.Collector
}
// Ensures that SQLite implements the OpenFGADatastore interface.
var _ storage.OpenFGADatastore = (*SQLite)(nil)
// New creates a new [SQLite] storage.
func New(uri string, cfg *Config) (*SQLite, error) {
// Set journal mode and busy timeout pragmas if not specified.
query := url.Values{}
var err error
if i := strings.Index(uri, "?"); i != -1 {
query, err = url.ParseQuery(uri[i+1:])
if err != nil {
return nil, fmt.Errorf("error parsing dsn: %w", err)
}
uri = uri[:i]
}
foundJournalMode := false
foundBusyTimeout := false
for _, val := range query["_pragma"] {
if strings.HasPrefix(val, "journal_mode") {
foundJournalMode = true
} else if strings.HasPrefix(val, "busy_timeout") {
foundBusyTimeout = true
}
}
if !foundJournalMode {
query.Add("_pragma", "journal_mode(WAL)")
}
if !foundBusyTimeout {
query.Add("_pragma", "busy_timeout(500)")
}
uri += "?" + query.Encode()
db, err := sql.Open("sqlite", uri)
if err != nil {
return nil, fmt.Errorf("initialize sqlite connection: %w", err)
}
return NewWithDB(db, cfg)
}
// NewWithDB creates a new [SQLite] storage using provided [*sql.DB]
func NewWithDB(db *sql.DB, cfg *Config) (*SQLite, error) {
var collector prometheus.Collector
if cfg.ExportMetrics {
collector = collectors.NewDBStatsCollector(db, "openfga")
if err := prometheus.Register(collector); err != nil {
return nil, fmt.Errorf("initialize metrics: %w", err)
}
}
sqlTime := sq.Expr("datetime('subsec')")
stbl := sq.StatementBuilder.RunWith(db)
dbInfo := sqlcommon.NewDBInfo(db, stbl, sqlTime)
return &SQLite{
cfg: cfg,
stbl: stbl,
db: db,
sqlTime: sqlTime,
dbInfo: dbInfo,
logger: cfg.Logger,
dbStatsCollector: collector,
}, nil
}
// Close see [storage.OpenFGADatastore].Close.
func (m *SQLite) Close() {
if m.dbStatsCollector != nil {
prometheus.Unregister(m.dbStatsCollector)
}
_ = m.db.Close()
}
// Read see [storage.RelationshipTupleReader].Read.
func (m *SQLite) Read(ctx context.Context, store string, tupleKey *openfgav1.TupleKey) (storage.TupleIterator, error) {
ctx, span := tracer.Start(ctx, "sqlite.Read")
defer span.End()
return m.read(ctx, store, tupleKey, nil)
}
// ReadPage see [storage.RelationshipTupleReader].ReadPage.
func (m *SQLite) ReadPage(
ctx context.Context,
store string,
tupleKey *openfgav1.TupleKey,
opts storage.PaginationOptions,
) ([]*openfgav1.Tuple, []byte, error) {
ctx, span := tracer.Start(ctx, "sqlite.ReadPage")
defer span.End()
iter, err := m.read(ctx, store, tupleKey, &opts)
if err != nil {
return nil, nil, err
}
defer iter.Stop()
return iter.ToArray(opts)
}
func (m *SQLite) read(ctx context.Context, store string, tupleKey *openfgav1.TupleKey, opts *storage.PaginationOptions) (*sqlcommon.SQLTupleIterator, error) {
ctx, span := tracer.Start(ctx, "sqlite.read")
defer span.End()
sb := m.stbl.
Select(
"store", "object_type", "object_id", "relation", "_user",
"condition_name", "condition_context", "ulid", "inserted_at",
).
From("tuple").
Where(sq.Eq{"store": store})
if opts != nil {
sb = sb.OrderBy("ulid")
}
objectType, objectID := tupleUtils.SplitObject(tupleKey.GetObject())
if objectType != "" {
sb = sb.Where(sq.Eq{"object_type": objectType})
}
if objectID != "" {
sb = sb.Where(sq.Eq{"object_id": objectID})
}
if tupleKey.GetRelation() != "" {
sb = sb.Where(sq.Eq{"relation": tupleKey.GetRelation()})
}
if tupleKey.GetUser() != "" {
sb = sb.Where(sq.Eq{"_user": tupleKey.GetUser()})
}
if opts != nil && opts.From != "" {
token, err := sqlcommon.UnmarshallContToken(opts.From)
if err != nil {
return nil, err
}
sb = sb.Where(sq.GtOrEq{"ulid": token.Ulid})
}
if opts != nil && opts.PageSize != 0 {
sb = sb.Limit(uint64(opts.PageSize + 1)) // + 1 is used to determine whether to return a continuation token.
}
rows, err := sb.QueryContext(ctx)
if err != nil {
return nil, handleSQLError(err)
}
return sqlcommon.NewSQLTupleIterator(rows), nil
}
// Write see [storage.RelationshipTupleWriter].Write.
func (m *SQLite) Write(ctx context.Context, store string, deletes storage.Deletes, writes storage.Writes) error {
ctx, span := tracer.Start(ctx, "sqlite.Write")
defer span.End()
if len(deletes)+len(writes) > m.MaxTuplesPerWrite() {
return storage.ErrExceededWriteBatchLimit
}
return m.busyRetry(func() error {
now := time.Now().UTC()
return write(ctx, m.db, m.stbl, m.sqlTime, store, deletes, writes, now)
})
}
// ReadUserTuple see [storage.RelationshipTupleReader].ReadUserTuple.
func (m *SQLite) ReadUserTuple(ctx context.Context, store string, tupleKey *openfgav1.TupleKey) (*openfgav1.Tuple, error) {
ctx, span := tracer.Start(ctx, "sqlite.ReadUserTuple")
defer span.End()
objectType, objectID := tupleUtils.SplitObject(tupleKey.GetObject())
userType := tupleUtils.GetUserTypeFromUser(tupleKey.GetUser())
var conditionName sql.NullString
var conditionContext []byte
var record storage.TupleRecord
err := m.stbl.
Select(
"object_type", "object_id", "relation", "_user",
"condition_name", "condition_context",
).
From("tuple").
Where(sq.Eq{
"store": store,
"object_type": objectType,
"object_id": objectID,
"relation": tupleKey.GetRelation(),
"_user": tupleKey.GetUser(),
"user_type": userType,
}).
QueryRowContext(ctx).
Scan(
&record.ObjectType,
&record.ObjectID,
&record.Relation,
&record.User,
&conditionName,
&conditionContext,
)
if err != nil {
return nil, handleSQLError(err)
}
if conditionName.String != "" {
record.ConditionName = conditionName.String
if conditionContext != nil {
var conditionContextStruct structpb.Struct
if err := proto.Unmarshal(conditionContext, &conditionContextStruct); err != nil {
return nil, err
}
record.ConditionContext = &conditionContextStruct
}
}
return record.AsTuple(), nil
}
// ReadUsersetTuples see [storage.RelationshipTupleReader].ReadUsersetTuples.
func (m *SQLite) ReadUsersetTuples(
ctx context.Context,
store string,
filter storage.ReadUsersetTuplesFilter,
) (storage.TupleIterator, error) {
ctx, span := tracer.Start(ctx, "sqlite.ReadUsersetTuples")
defer span.End()
sb := m.stbl.
Select(
"store", "object_type", "object_id", "relation", "_user",
"condition_name", "condition_context", "ulid", "inserted_at",
).
From("tuple").
Where(sq.Eq{"store": store}).
Where(sq.Eq{"user_type": tupleUtils.UserSet})
objectType, objectID := tupleUtils.SplitObject(filter.Object)
if objectType != "" {
sb = sb.Where(sq.Eq{"object_type": objectType})
}
if objectID != "" {
sb = sb.Where(sq.Eq{"object_id": objectID})
}
if filter.Relation != "" {
sb = sb.Where(sq.Eq{"relation": filter.Relation})
}
if len(filter.AllowedUserTypeRestrictions) > 0 {
orConditions := sq.Or{}
for _, userset := range filter.AllowedUserTypeRestrictions {
if _, ok := userset.GetRelationOrWildcard().(*openfgav1.RelationReference_Relation); ok {
orConditions = append(orConditions, sq.Like{"_user": userset.GetType() + ":%#" + userset.GetRelation()})
}
if _, ok := userset.GetRelationOrWildcard().(*openfgav1.RelationReference_Wildcard); ok {
orConditions = append(orConditions, sq.Eq{"_user": userset.GetType() + ":*"})
}
}
sb = sb.Where(orConditions)
}
rows, err := sb.QueryContext(ctx)
if err != nil {
return nil, handleSQLError(err)
}
return sqlcommon.NewSQLTupleIterator(rows), nil
}
// ReadStartingWithUser see [storage.RelationshipTupleReader].ReadStartingWithUser.
func (m *SQLite) ReadStartingWithUser(
ctx context.Context,
store string,
opts storage.ReadStartingWithUserFilter,
) (storage.TupleIterator, error) {
ctx, span := tracer.Start(ctx, "sqlite.ReadStartingWithUser")
defer span.End()
targetUsersArg := make([]string, 0, len(opts.UserFilter))
for _, u := range opts.UserFilter {
targetUser := u.GetObject()
if u.GetRelation() != "" {
targetUser = strings.Join([]string{u.GetObject(), u.GetRelation()}, "#")
}
targetUsersArg = append(targetUsersArg, targetUser)
}
rows, err := m.stbl.
Select(
"store", "object_type", "object_id", "relation", "_user",
"condition_name", "condition_context", "ulid", "inserted_at",
).
From("tuple").
Where(sq.Eq{
"store": store,
"object_type": opts.ObjectType,
"relation": opts.Relation,
"_user": targetUsersArg,
}).QueryContext(ctx)
if err != nil {
return nil, handleSQLError(err)
}
return sqlcommon.NewSQLTupleIterator(rows), nil
}
// MaxTuplesPerWrite see [storage.RelationshipTupleWriter].MaxTuplesPerWrite.
func (m *SQLite) MaxTuplesPerWrite() int {
return m.cfg.MaxTuplesPerWriteField
}
// ReadAuthorizationModel see [storage.AuthorizationModelReadBackend].ReadAuthorizationModel.
func (m *SQLite) ReadAuthorizationModel(ctx context.Context, store string, modelID string) (*openfgav1.AuthorizationModel, error) {
ctx, span := tracer.Start(ctx, "sqlite.ReadAuthorizationModel")
defer span.End()
return sqlcommon.ReadAuthorizationModel(ctx, m.dbInfo, store, modelID)
}
// ReadAuthorizationModels see [storage.AuthorizationModelReadBackend].ReadAuthorizationModels.
func (m *SQLite) ReadAuthorizationModels(
ctx context.Context,
store string,
opts storage.PaginationOptions,
) ([]*openfgav1.AuthorizationModel, []byte, error) {
ctx, span := tracer.Start(ctx, "sqlite.ReadAuthorizationModels")
defer span.End()
sb := m.stbl.Select("authorization_model_id").
Distinct().
From("authorization_model").
Where(sq.Eq{"store": store}).
OrderBy("authorization_model_id desc")
if opts.From != "" {
token, err := sqlcommon.UnmarshallContToken(opts.From)
if err != nil {
return nil, nil, err
}
sb = sb.Where(sq.LtOrEq{"authorization_model_id": token.Ulid})
}
if opts.PageSize > 0 {
sb = sb.Limit(uint64(opts.PageSize + 1)) // + 1 is used to determine whether to return a continuation token.
}
rows, err := sb.QueryContext(ctx)
if err != nil {
return nil, nil, handleSQLError(err)
}
defer func() { _ = rows.Close() }()
var modelIDs []string
var modelID string
for rows.Next() {
err = rows.Scan(&modelID)
if err != nil {
return nil, nil, handleSQLError(err)
}
modelIDs = append(modelIDs, modelID)
}
if err := rows.Err(); err != nil {
return nil, nil, handleSQLError(err)
}
var token []byte
numModelIDs := len(modelIDs)
if len(modelIDs) > opts.PageSize {
numModelIDs = opts.PageSize
token, err = json.Marshal(sqlcommon.NewContToken(modelID, ""))
if err != nil {
return nil, nil, err
}
}
// TODO: make this concurrent with a maximum of 5 goroutines. This may be helpful:
// https://stackoverflow.com/questions/25306073/always-have-x-number-of-goroutines-running-at-any-time
models := make([]*openfgav1.AuthorizationModel, 0, numModelIDs)
// We use numModelIDs here to avoid retrieving possibly one extra model.
for i := 0; i < numModelIDs; i++ {
model, err := m.ReadAuthorizationModel(ctx, store, modelIDs[i])
if err != nil {
return nil, nil, err
}
models = append(models, model)
}
return models, token, nil
}
// FindLatestAuthorizationModel see [storage.AuthorizationModelReadBackend].FindLatestAuthorizationModel.
func (m *SQLite) FindLatestAuthorizationModel(ctx context.Context, store string) (*openfgav1.AuthorizationModel, error) {
ctx, span := tracer.Start(ctx, "sqlite.FindLatestAuthorizationModel")
defer span.End()
return sqlcommon.FindLatestAuthorizationModel(ctx, m.dbInfo, store)
}
// MaxTypesPerAuthorizationModel see [storage.TypeDefinitionWriteBackend].MaxTypesPerAuthorizationModel.
func (m *SQLite) MaxTypesPerAuthorizationModel() int {
return m.cfg.MaxTypesPerModelField
}
// WriteAuthorizationModel see [storage.TypeDefinitionWriteBackend].WriteAuthorizationModel.
func (m *SQLite) WriteAuthorizationModel(ctx context.Context, store string, model *openfgav1.AuthorizationModel) error {
ctx, span := tracer.Start(ctx, "sqlite.WriteAuthorizationModel")
defer span.End()
typeDefinitions := model.GetTypeDefinitions()
if len(typeDefinitions) > m.MaxTypesPerAuthorizationModel() {
return storage.ExceededMaxTypeDefinitionsLimitError(m.MaxTypesPerAuthorizationModel())
}
return m.busyRetry(func() error {
return sqlcommon.WriteAuthorizationModel(ctx, m.dbInfo, store, model)
})
}
// CreateStore adds a new store to the SQLite storage.
func (m *SQLite) CreateStore(ctx context.Context, store *openfgav1.Store) (*openfgav1.Store, error) {
ctx, span := tracer.Start(ctx, "sqlite.CreateStore")
defer span.End()
txn, err := m.db.BeginTx(ctx, &sql.TxOptions{})
if err != nil {
return nil, handleSQLError(err)
}
defer func() {
_ = txn.Rollback()
}()
_, err = m.stbl.
Insert("store").
Columns("id", "name", "created_at", "updated_at").
Values(store.GetId(), store.GetName(), sq.Expr("datetime('subsec')"), sq.Expr("datetime('subsec')")).
RunWith(txn).
ExecContext(ctx)
if err != nil {
return nil, handleSQLError(err)
}
var createdAt time.Time
var id, name string
err = m.stbl.
Select("id", "name", "created_at").
From("store").
Where(sq.Eq{"id": store.GetId()}).
RunWith(txn).
QueryRowContext(ctx).
Scan(&id, &name, &createdAt)
if err != nil {
return nil, handleSQLError(err)
}
err = txn.Commit()
if err != nil {
return nil, handleSQLError(err)
}
return &openfgav1.Store{
Id: id,
Name: name,
CreatedAt: timestamppb.New(createdAt),
UpdatedAt: timestamppb.New(createdAt),
}, nil
}
// GetStore retrieves the details of a specific store from the SQLite using its storeID.
func (m *SQLite) GetStore(ctx context.Context, id string) (*openfgav1.Store, error) {
ctx, span := tracer.Start(ctx, "sqlite.GetStore")
defer span.End()
row := m.stbl.
Select("id", "name", "created_at", "updated_at").
From("store").
Where(sq.Eq{
"id": id,
"deleted_at": nil,
}).
QueryRowContext(ctx)
var storeID, name string
var createdAt, updatedAt time.Time
err := row.Scan(&storeID, &name, &createdAt, &updatedAt)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, storage.ErrNotFound
}
return nil, handleSQLError(err)
}
return &openfgav1.Store{
Id: storeID,
Name: name,
CreatedAt: timestamppb.New(createdAt),
UpdatedAt: timestamppb.New(updatedAt),
}, nil
}
// ListStores provides a paginated list of all stores present in the SQLite storage.
func (m *SQLite) ListStores(ctx context.Context, opts storage.PaginationOptions) ([]*openfgav1.Store, []byte, error) {
ctx, span := tracer.Start(ctx, "sqlite.ListStores")
defer span.End()
sb := m.stbl.
Select("id", "name", "created_at", "updated_at").
From("store").
Where(sq.Eq{"deleted_at": nil}).
OrderBy("id")
if opts.From != "" {
token, err := sqlcommon.UnmarshallContToken(opts.From)
if err != nil {
return nil, nil, err
}
sb = sb.Where(sq.GtOrEq{"id": token.Ulid})
}
if opts.PageSize > 0 {
sb = sb.Limit(uint64(opts.PageSize + 1)) // + 1 is used to determine whether to return a continuation token.
}
rows, err := sb.QueryContext(ctx)
if err != nil {
return nil, nil, handleSQLError(err)
}
defer func() { _ = rows.Close() }()
var stores []*openfgav1.Store
var id string
for rows.Next() {
var name string
var createdAt, updatedAt time.Time
err := rows.Scan(&id, &name, &createdAt, &updatedAt)
if err != nil {
return nil, nil, handleSQLError(err)
}
stores = append(stores, &openfgav1.Store{
Id: id,
Name: name,
CreatedAt: timestamppb.New(createdAt),
UpdatedAt: timestamppb.New(updatedAt),
})
}
if err := rows.Err(); err != nil {
return nil, nil, handleSQLError(err)
}
if len(stores) > opts.PageSize {
contToken, err := json.Marshal(sqlcommon.NewContToken(id, ""))
if err != nil {
return nil, nil, err
}
return stores[:opts.PageSize], contToken, nil
}
return stores, nil, nil
}
// DeleteStore removes a store from the SQLite storage.
func (m *SQLite) DeleteStore(ctx context.Context, id string) error {
ctx, span := tracer.Start(ctx, "sqlite.DeleteStore")
defer span.End()
_, err := m.stbl.
Update("store").
Set("deleted_at", sq.Expr("datetime('subsec')")).
Where(sq.Eq{"id": id}).
ExecContext(ctx)
if err != nil {
return handleSQLError(err)
}
return nil
}
// WriteAssertions see [storage.AssertionsBackend].WriteAssertions.
func (m *SQLite) WriteAssertions(ctx context.Context, store, modelID string, assertions []*openfgav1.Assertion) error {
ctx, span := tracer.Start(ctx, "sqlite.WriteAssertions")
defer span.End()
marshalledAssertions, err := proto.Marshal(&openfgav1.Assertions{Assertions: assertions})
if err != nil {
return err
}
return m.busyRetry(func() error {
_, err = m.stbl.
Insert("assertion").
Columns("store", "authorization_model_id", "assertions").
Values(store, modelID, marshalledAssertions).
Suffix("ON CONFLICT(store,authorization_model_id) DO UPDATE SET assertions = ?", marshalledAssertions).
ExecContext(ctx)
if err != nil {
return handleSQLError(err)
}
return nil
})
}
// ReadAssertions see [storage.AssertionsBackend].ReadAssertions.
func (m *SQLite) ReadAssertions(ctx context.Context, store, modelID string) ([]*openfgav1.Assertion, error) {
ctx, span := tracer.Start(ctx, "sqlite.ReadAssertions")
defer span.End()
var marshalledAssertions []byte
err := m.stbl.
Select("assertions").
From("assertion").
Where(sq.Eq{
"store": store,
"authorization_model_id": modelID,
}).
QueryRowContext(ctx).
Scan(&marshalledAssertions)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return []*openfgav1.Assertion{}, nil
}
return nil, handleSQLError(err)
}
var assertions openfgav1.Assertions
err = proto.Unmarshal(marshalledAssertions, &assertions)
if err != nil {
return nil, err
}
return assertions.GetAssertions(), nil
}
// ReadChanges see [storage.ChangelogBackend].ReadChanges.
func (m *SQLite) ReadChanges(
ctx context.Context,
store, objectTypeFilter string,
opts storage.PaginationOptions,
horizonOffset time.Duration,
) ([]*openfgav1.TupleChange, []byte, error) {
ctx, span := tracer.Start(ctx, "sqlite.ReadChanges")
defer span.End()
sb := m.stbl.
Select(
"ulid", "object_type", "object_id", "relation", "_user", "operation",
"condition_name", "condition_context", "inserted_at",
).
From("changelog").
Where(sq.Eq{"store": store}).
Where(fmt.Sprintf("inserted_at <= datetime('subsec','-%f seconds')", horizonOffset.Seconds())).
OrderBy("ulid asc")
if objectTypeFilter != "" {
sb = sb.Where(sq.Eq{"object_type": objectTypeFilter})
}
if opts.From != "" {
token, err := sqlcommon.UnmarshallContToken(opts.From)
if err != nil {
return nil, nil, err
}
if token.ObjectType != objectTypeFilter {
return nil, nil, storage.ErrMismatchObjectType
}
sb = sb.Where(sq.Gt{"ulid": token.Ulid}) // > as we always return a continuation token.
}
if opts.PageSize > 0 {
sb = sb.Limit(uint64(opts.PageSize)) // + 1 is NOT used here as we always return a continuation token.
}
rows, err := sb.QueryContext(ctx)
if err != nil {
return nil, nil, handleSQLError(err)
}
defer func() { _ = rows.Close() }()
var changes []*openfgav1.TupleChange
var ulid string
for rows.Next() {
var objectType, objectID, relation, user string
var operation int
var insertedAt time.Time
var conditionName sql.NullString
var conditionContext []byte
err = rows.Scan(
&ulid,
&objectType,
&objectID,
&relation,
&user,
&operation,
&conditionName,
&conditionContext,
&insertedAt,
)
if err != nil {
return nil, nil, handleSQLError(err)
}
var conditionContextStruct structpb.Struct
if conditionName.String != "" {
if conditionContext != nil {
if err := proto.Unmarshal(conditionContext, &conditionContextStruct); err != nil {
return nil, nil, err
}
}
}
tk := tupleUtils.NewTupleKeyWithCondition(
tupleUtils.BuildObject(objectType, objectID),
relation,
user,
conditionName.String,
&conditionContextStruct,
)
changes = append(changes, &openfgav1.TupleChange{
TupleKey: tk,
Operation: openfgav1.TupleOperation(operation),
Timestamp: timestamppb.New(insertedAt.UTC()),
})
}
if len(changes) == 0 {
return nil, nil, storage.ErrNotFound
}
contToken, err := json.Marshal(sqlcommon.NewContToken(ulid, objectTypeFilter))
if err != nil {
return nil, nil, err
}
return changes, contToken, nil
}
func (m *SQLite) IsReady(ctx context.Context) (storage.ReadinessStatus, error) {
if err := m.db.PingContext(ctx); err != nil {
return storage.ReadinessStatus{}, err
}
return storage.ReadinessStatus{
IsReady: true,
}, nil
}
// SQLite will return an SQLITE_BUSY error when the database is locked rather than waiting for the lock.
// This function retries the operation up to 5 times before returning the error.
func (m *SQLite) busyRetry(fn func() error) error {
for retries := 0; ; retries++ {
err := fn()
if err == nil || retries == m.cfg.QueryRetries {
return err
}
var sqliteErr *sqlite3.Error
if errors.As(err, &sqliteErr) && (sqliteErr.Code == sqlite3.ErrLocked || sqliteErr.Code == sqlite3.ErrBusy) {
time.Sleep(10 * time.Millisecond)
continue
}
return err
}
}
func handleSQLError(err error, args ...any) error {
if strings.Contains(err.Error(), "UNIQUE constraint failed:") {
if len(args) > 0 {
if tk, ok := args[0].(*openfgav1.TupleKey); ok {
return storage.InvalidWriteInputError(tk, openfgav1.TupleOperation_TUPLE_OPERATION_WRITE)
}
}
return storage.ErrCollision
}
return sqlcommon.HandleSQLError(err, args...)
}
@@ -1,295 +0,0 @@
package sqlite
import (
"context"
"database/sql"
"testing"
"time"
sq "github.com/Masterminds/squirrel"
"github.com/oklog/ulid/v2"
openfgav1 "github.com/openfga/api/proto/openfga/v1"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
"github.com/openfga/openfga/pkg/storage"
"github.com/openfga/openfga/pkg/storage/sqlcommon"
"github.com/openfga/openfga/pkg/storage/test"
"github.com/openfga/openfga/pkg/tuple"
"github.com/openfga/openfga/pkg/typesystem"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
"github.com/grafana/grafana/pkg/tests/testsuite"
zassets "github.com/grafana/grafana/pkg/services/authz/zanzana/store/assets"
"github.com/grafana/grafana/pkg/services/authz/zanzana/store/migration"
)
func TestMain(m *testing.M) {
testsuite.Run(m)
}
// TestIntegrationDatastore runs open fga default datastore test suite
func TestIntegrationDatastore(t *testing.T) {
db := sqliteIntegrationTest(t)
ds, err := NewWithDB(db, NewConfig())
require.NoError(t, err)
test.RunAllTests(t, ds)
}
// TestIntegrationReadEnsureNoOrder asserts that the read response is not ordered by ulid.
func TestIntegrationReadEnsureNoOrder(t *testing.T) {
db := sqliteIntegrationTest(t)
ds, err := NewWithDB(db, NewConfig())
require.NoError(t, err)
ctx := context.Background()
store := "store"
firstTuple := tuple.NewTupleKey("doc:object_id_1", "relation", "user:user_1")
secondTuple := tuple.NewTupleKey("doc:object_id_2", "relation", "user:user_2")
err = sqlcommon.Write(ctx,
sqlcommon.NewDBInfo(ds.db, ds.stbl, sq.Expr("datetime('subsec')")),
store,
[]*openfgav1.TupleKeyWithoutCondition{},
[]*openfgav1.TupleKey{firstTuple},
time.Now())
require.NoError(t, err)
// Tweak time so that ULID is smaller.
err = sqlcommon.Write(ctx,
sqlcommon.NewDBInfo(ds.db, ds.stbl, sq.Expr("datetime('subsec')")),
store,
[]*openfgav1.TupleKeyWithoutCondition{},
[]*openfgav1.TupleKey{secondTuple},
time.Now().Add(time.Minute*-1))
require.NoError(t, err)
iter, err := ds.Read(ctx,
store,
tuple.NewTupleKey("doc:", "relation", ""))
defer iter.Stop()
require.NoError(t, err)
// We expect that objectID1 will return first because it is inserted first.
curTuple, err := iter.Next(ctx)
require.NoError(t, err)
require.Equal(t, firstTuple, curTuple.GetKey())
curTuple, err = iter.Next(ctx)
require.NoError(t, err)
require.Equal(t, secondTuple, curTuple.GetKey())
}
// TestIntegrationReadPageEnsureNoOrder asserts that the read page is ordered by ulid.
func TestIntegrationReadPageEnsureOrder(t *testing.T) {
db := sqliteIntegrationTest(t)
ds, err := NewWithDB(db, NewConfig())
require.NoError(t, err)
ctx := context.Background()
store := "store"
firstTuple := tuple.NewTupleKey("doc:object_id_1", "relation", "user:user_1")
secondTuple := tuple.NewTupleKey("doc:object_id_2", "relation", "user:user_2")
err = sqlcommon.Write(ctx,
sqlcommon.NewDBInfo(ds.db, ds.stbl, sq.Expr("datetime('subsec')")),
store,
[]*openfgav1.TupleKeyWithoutCondition{},
[]*openfgav1.TupleKey{firstTuple},
time.Now())
require.NoError(t, err)
// Tweak time so that ULID is smaller.
err = sqlcommon.Write(ctx,
sqlcommon.NewDBInfo(ds.db, ds.stbl, sq.Expr("datetime('subsec')")),
store,
[]*openfgav1.TupleKeyWithoutCondition{},
[]*openfgav1.TupleKey{secondTuple},
time.Now().Add(time.Minute*-1))
require.NoError(t, err)
tuples, _, err := ds.ReadPage(ctx,
store,
tuple.NewTupleKey("doc:", "relation", ""),
storage.NewPaginationOptions(0, ""))
require.NoError(t, err)
require.Len(t, tuples, 2)
// We expect that objectID2 will return first because it has a smaller ulid.
require.Equal(t, secondTuple, tuples[0].GetKey())
require.Equal(t, firstTuple, tuples[1].GetKey())
}
func TestIntegrationReadAuthorizationModelUnmarshallError(t *testing.T) {
db := sqliteIntegrationTest(t)
ds, err := NewWithDB(db, NewConfig())
require.NoError(t, err)
ctx := context.Background()
store := "store"
modelID := "foo"
schemaVersion := typesystem.SchemaVersion1_0
bytes, err := proto.Marshal(&openfgav1.TypeDefinition{Type: "document"})
require.NoError(t, err)
pbdata := []byte{0x01, 0x02, 0x03}
_, err = ds.db.ExecContext(ctx, "INSERT INTO authorization_model (store, authorization_model_id, schema_version, type, type_definition, serialized_protobuf) VALUES (?, ?, ?, ?, ?, ?)", store, modelID, schemaVersion, "document", bytes, pbdata)
require.NoError(t, err)
_, err = ds.ReadAuthorizationModel(ctx, store, modelID)
require.Error(t, err)
require.Contains(t, err.Error(), "cannot parse invalid wire-format data")
}
// TestIntegrationAllowNullCondition tests that tuple and changelog rows existing before
// migration 005_add_conditions_to_tuples can be successfully read.
func TestIntegrationAllowNullCondition(t *testing.T) {
db := sqliteIntegrationTest(t)
ds, err := NewWithDB(db, NewConfig())
require.NoError(t, err)
ctx := context.Background()
stmt := `
INSERT INTO tuple (
store, object_type, object_id, relation, _user, user_type, ulid,
condition_name, condition_context, inserted_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('subsec'));
`
_, err = ds.db.ExecContext(
ctx, stmt, "store", "folder", "2021-budget", "owner", "user:anne", "user",
ulid.Make().String(), nil, nil,
)
require.NoError(t, err)
tk := tuple.NewTupleKey("folder:2021-budget", "owner", "user:anne")
iter, err := ds.Read(ctx, "store", tk)
require.NoError(t, err)
defer iter.Stop()
curTuple, err := iter.Next(ctx)
require.NoError(t, err)
require.Equal(t, tk, curTuple.GetKey())
tuples, _, err := ds.ReadPage(ctx, "store", &openfgav1.TupleKey{}, storage.PaginationOptions{
PageSize: 2,
})
require.NoError(t, err)
require.Len(t, tuples, 1)
require.Equal(t, tk, tuples[0].GetKey())
userTuple, err := ds.ReadUserTuple(ctx, "store", tk)
require.NoError(t, err)
require.Equal(t, tk, userTuple.GetKey())
tk2 := tuple.NewTupleKey("folder:2022-budget", "viewer", "user:anne")
_, err = ds.db.ExecContext(
ctx, stmt, "store", "folder", "2022-budget", "viewer", "user:anne", "userset",
ulid.Make().String(), nil, nil,
)
require.NoError(t, err)
iter, err = ds.ReadUsersetTuples(ctx, "store", storage.ReadUsersetTuplesFilter{Object: "folder:2022-budget"})
require.NoError(t, err)
defer iter.Stop()
curTuple, err = iter.Next(ctx)
require.NoError(t, err)
require.Equal(t, tk2, curTuple.GetKey())
iter, err = ds.ReadStartingWithUser(ctx, "store", storage.ReadStartingWithUserFilter{
ObjectType: "folder",
Relation: "owner",
UserFilter: []*openfgav1.ObjectRelation{
{Object: "user:anne"},
},
})
require.NoError(t, err)
defer iter.Stop()
curTuple, err = iter.Next(ctx)
require.NoError(t, err)
require.Equal(t, tk, curTuple.GetKey())
stmt = `
INSERT INTO changelog (
store, object_type, object_id, relation, _user, ulid,
condition_name, condition_context, inserted_at, operation
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, datetime('subsec'), ?);
`
_, err = ds.db.ExecContext(
ctx, stmt, "store", "folder", "2021-budget", "owner", "user:anne",
ulid.Make().String(), nil, nil, openfgav1.TupleOperation_TUPLE_OPERATION_WRITE,
)
require.NoError(t, err)
_, err = ds.db.ExecContext(
ctx, stmt, "store", "folder", "2021-budget", "owner", "user:anne",
ulid.Make().String(), nil, nil, openfgav1.TupleOperation_TUPLE_OPERATION_DELETE,
)
require.NoError(t, err)
changes, _, err := ds.ReadChanges(ctx, "store", "folder", storage.PaginationOptions{}, 0)
require.NoError(t, err)
require.Len(t, changes, 2)
require.Equal(t, tk, changes[0].GetTupleKey())
require.Equal(t, tk, changes[1].GetTupleKey())
}
// TestIntegrationMarshalledAssertions tests that previously persisted marshalled
// assertions can be read back. In any case where the Assertions proto model
// needs to change, we'll likely need to introduce a series of data migrations.
func TestIntegrationMarshalledAssertions(t *testing.T) {
db := sqliteIntegrationTest(t)
ds, err := NewWithDB(db, NewConfig())
require.NoError(t, err)
ctx := context.Background()
// Note: this represents an assertion written on v1.3.7.
stmt := `
INSERT INTO assertion (
store, authorization_model_id, assertions
) VALUES (?, ?, UNHEX('0A2B0A270A12666F6C6465723A323032312D62756467657412056F776E65721A0A757365723A616E6E657A1001'));
`
_, err = ds.db.ExecContext(ctx, stmt, "store", "model")
require.NoError(t, err)
assertions, err := ds.ReadAssertions(ctx, "store", "model")
require.NoError(t, err)
expectedAssertions := []*openfgav1.Assertion{
{
TupleKey: &openfgav1.AssertionTupleKey{
Object: "folder:2021-budget",
Relation: "owner",
User: "user:annez",
},
Expectation: true,
},
}
require.Equal(t, expectedAssertions, assertions)
}
func sqliteIntegrationTest(tb testing.TB) *sql.DB {
if testing.Short() || !db.IsTestDbSQLite() {
tb.Skip("skipping integration test")
}
db, cfg := db.InitTestDBWithCfg(tb)
m := migrator.NewMigrator(db.GetEngine(), cfg)
err := migration.RunWithMigrator(m, cfg, zassets.EmbedMigrations, zassets.SQLiteMigrationDir)
require.NoError(tb, err)
return db.GetEngine().DB().DB
}
@@ -1,165 +0,0 @@
package sqlite
import (
"context"
"database/sql"
"time"
sq "github.com/Masterminds/squirrel"
"github.com/oklog/ulid/v2"
"google.golang.org/protobuf/proto"
openfgav1 "github.com/openfga/api/proto/openfga/v1"
"github.com/openfga/openfga/pkg/storage"
tupleUtils "github.com/openfga/openfga/pkg/tuple"
)
// write is copied from https://github.com/openfga/openfga/blob/main/pkg/storage/sqlcommon/sqlcommon.go#L330-L456
// but uses custom handleSQLError.
func write(
ctx context.Context,
db *sql.DB,
stbl sq.StatementBuilderType,
sqlTime any,
store string,
deletes storage.Deletes,
writes storage.Writes,
now time.Time,
) error {
txn, err := db.BeginTx(ctx, nil)
if err != nil {
return handleSQLError(err)
}
defer func() {
_ = txn.Rollback()
}()
changelogBuilder := stbl.
Insert("changelog").
Columns(
"store", "object_type", "object_id", "relation", "_user",
"condition_name", "condition_context", "operation", "ulid", "inserted_at",
)
deleteBuilder := stbl.Delete("tuple")
for _, tk := range deletes {
id := ulid.MustNew(ulid.Timestamp(now), ulid.DefaultEntropy()).String()
objectType, objectID := tupleUtils.SplitObject(tk.GetObject())
res, err := deleteBuilder.
Where(sq.Eq{
"store": store,
"object_type": objectType,
"object_id": objectID,
"relation": tk.GetRelation(),
"_user": tk.GetUser(),
"user_type": tupleUtils.GetUserTypeFromUser(tk.GetUser()),
}).
RunWith(txn). // Part of a txn.
ExecContext(ctx)
if err != nil {
return handleSQLError(err, tk)
}
rowsAffected, err := res.RowsAffected()
if err != nil {
return handleSQLError(err)
}
if rowsAffected != 1 {
return storage.InvalidWriteInputError(
tk,
openfgav1.TupleOperation_TUPLE_OPERATION_DELETE,
)
}
changelogBuilder = changelogBuilder.Values(
store, objectType, objectID,
tk.GetRelation(), tk.GetUser(),
"", nil, // Redact condition info for deletes since we only need the base triplet (object, relation, user).
openfgav1.TupleOperation_TUPLE_OPERATION_DELETE,
id, sqlTime,
)
}
insertBuilder := stbl.
Insert("tuple").
Columns(
"store", "object_type", "object_id", "relation", "_user", "user_type",
"condition_name", "condition_context", "ulid", "inserted_at",
)
for _, tk := range writes {
id := ulid.MustNew(ulid.Timestamp(now), ulid.DefaultEntropy()).String()
objectType, objectID := tupleUtils.SplitObject(tk.GetObject())
conditionName, conditionContext, err := marshalRelationshipCondition(tk.GetCondition())
if err != nil {
return err
}
_, err = insertBuilder.
Values(
store,
objectType,
objectID,
tk.GetRelation(),
tk.GetUser(),
tupleUtils.GetUserTypeFromUser(tk.GetUser()),
conditionName,
conditionContext,
id,
sqlTime,
).
RunWith(txn). // Part of a txn.
ExecContext(ctx)
if err != nil {
return handleSQLError(err, tk)
}
changelogBuilder = changelogBuilder.Values(
store,
objectType,
objectID,
tk.GetRelation(),
tk.GetUser(),
conditionName,
conditionContext,
openfgav1.TupleOperation_TUPLE_OPERATION_WRITE,
id,
sqlTime,
)
}
if len(writes) > 0 || len(deletes) > 0 {
_, err := changelogBuilder.RunWith(txn).ExecContext(ctx) // Part of a txn.
if err != nil {
return handleSQLError(err)
}
}
if err := txn.Commit(); err != nil {
return handleSQLError(err)
}
return nil
}
// copied from https://github.com/openfga/openfga/blob/main/pkg/storage/sqlcommon/encoding.go#L8-L24
func marshalRelationshipCondition(
rel *openfgav1.RelationshipCondition,
) (name string, context []byte, err error) {
if rel != nil {
if rel.GetContext() != nil && len(rel.GetContext().GetFields()) > 0 {
context, err = proto.Marshal(rel.GetContext())
if err != nil {
return name, context, err
}
}
return rel.GetName(), context, err
}
return name, context, err
}
+15 -25
View File
@@ -2,15 +2,15 @@ package store
import (
"fmt"
"strings"
"time"
"xorm.io/xorm"
"github.com/openfga/openfga/assets"
"github.com/openfga/openfga/pkg/storage"
"github.com/openfga/openfga/pkg/storage/mysql"
"github.com/openfga/openfga/pkg/storage/postgres"
"github.com/openfga/openfga/pkg/storage/sqlcommon"
"github.com/openfga/openfga/pkg/storage/sqlite"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/log"
@@ -19,9 +19,7 @@ import (
"github.com/grafana/grafana/pkg/setting"
zlogger "github.com/grafana/grafana/pkg/services/authz/zanzana/logger"
zassets "github.com/grafana/grafana/pkg/services/authz/zanzana/store/assets"
"github.com/grafana/grafana/pkg/services/authz/zanzana/store/migration"
"github.com/grafana/grafana/pkg/services/authz/zanzana/store/sqlite"
)
func NewStore(cfg *setting.Cfg, logger log.Logger) (storage.OpenFGADatastore, error) {
@@ -32,22 +30,12 @@ func NewStore(cfg *setting.Cfg, logger log.Logger) (storage.OpenFGADatastore, er
switch grafanaDBCfg.Type {
case migrator.SQLite:
connStr := grafanaDBCfg.ConnectionString
// Initilize connection using xorm engine so we can reuse it for both migrations and data store
engine, err := xorm.NewEngine(grafanaDBCfg.Type, connStr)
if err != nil {
return nil, fmt.Errorf("failed to connect to database: %w", err)
}
m := migrator.NewMigrator(engine, cfg)
if err := migration.RunWithMigrator(m, cfg, zassets.EmbedMigrations, zassets.SQLiteMigrationDir); err != nil {
connStr := sqliteConnectionString(grafanaDBCfg.ConnectionString)
if err := migration.Run(cfg, migrator.SQLite, connStr, assets.EmbedMigrations, assets.SqliteMigrationDir); err != nil {
return nil, fmt.Errorf("failed to run migrations: %w", err)
}
return sqlite.NewWithDB(engine.DB().DB, &sqlite.Config{
Config: zanzanaDBCfg,
QueryRetries: grafanaDBCfg.QueryRetries,
})
return sqlite.New(connStr, zanzanaDBCfg)
case migrator.MySQL:
// For mysql we need to pass parseTime parameter in connection string
connStr := grafanaDBCfg.ConnectionString + "&parseTime=true"
@@ -75,20 +63,16 @@ func NewEmbeddedStore(cfg *setting.Cfg, db db.DB, logger log.Logger) (storage.Op
return nil, fmt.Errorf("failed to parse database config: %w", err)
}
m := migrator.NewMigrator(db.GetEngine(), cfg)
switch grafanaDBCfg.Type {
case migrator.SQLite:
if err := migration.RunWithMigrator(m, cfg, zassets.EmbedMigrations, zassets.SQLiteMigrationDir); err != nil {
grafanaDBCfg.ConnectionString = sqliteConnectionString(grafanaDBCfg.ConnectionString)
if err := migration.Run(cfg, migrator.SQLite, grafanaDBCfg.ConnectionString, assets.EmbedMigrations, assets.SqliteMigrationDir); err != nil {
return nil, fmt.Errorf("failed to run migrations: %w", err)
}
// FIXME(kalleep): We should work on getting sqlite implemtation merged upstream and replace this one
return sqlite.NewWithDB(db.GetEngine().DB().DB, &sqlite.Config{
Config: zanzanaDBCfg,
QueryRetries: grafanaDBCfg.QueryRetries,
})
return sqlite.New(grafanaDBCfg.ConnectionString, zanzanaDBCfg)
case migrator.MySQL:
m := migrator.NewMigrator(db.GetEngine(), cfg)
if err := migration.RunWithMigrator(m, cfg, assets.EmbedMigrations, assets.MySQLMigrationDir); err != nil {
return nil, fmt.Errorf("failed to run migrations: %w", err)
}
@@ -96,6 +80,7 @@ func NewEmbeddedStore(cfg *setting.Cfg, db db.DB, logger log.Logger) (storage.Op
// For mysql we need to pass parseTime parameter in connection string
return mysql.New(grafanaDBCfg.ConnectionString+"&parseTime=true", zanzanaDBCfg)
case migrator.Postgres:
m := migrator.NewMigrator(db.GetEngine(), cfg)
if err := migration.RunWithMigrator(m, cfg, assets.EmbedMigrations, assets.PostgresMigrationDir); err != nil {
return nil, fmt.Errorf("failed to run migrations: %w", err)
}
@@ -126,3 +111,8 @@ func parseConfig(cfg *setting.Cfg, logger log.Logger) (*sqlstore.DatabaseConfig,
return grafanaDBCfg, zanzanaDBCfg, nil
}
func sqliteConnectionString(v string) string {
// hardcode zanzana.db for now
return v[0:strings.LastIndex(v, "/")+1] + "zanzana.db"
}
+5
View File
@@ -118,3 +118,8 @@ func TranslateFixedRole(role string) string {
role = strings.ReplaceAll(role, ".", "_")
return role
}
// Translate "read" for the dashboard into "dashboard_read" for folder
func TranslateToFolderRelation(relation, objectType string) string {
return fmt.Sprintf("%s_%s", objectType, relation)
}
+48 -71
View File
@@ -10,10 +10,11 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/grafana/authlib/claims"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/authz/zanzana"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
)
const (
@@ -193,9 +194,16 @@ func (dr *DashboardServiceImpl) checkDashboards(ctx context.Context, query dashb
}
req := accesscontrol.CheckRequest{
User: query.SignedInUser.GetUID(),
Relation: "read",
Object: zanzana.NewScopedTupleEntry(objectType, d.UID, "", strconv.FormatInt(orgId, 10)),
Namespace: claims.OrgNamespaceFormatter(orgId),
User: query.SignedInUser.GetUID(),
Relation: "read",
Object: zanzana.NewScopedTupleEntry(objectType, d.UID, "", strconv.FormatInt(orgId, 10)),
}
if objectType != zanzana.TypeFolder {
// Pass parentn folder for the correct check
req.Parent = d.FolderUID
req.ObjectType = objectType
}
allowed, err := dr.ac.Check(ctx, req)
@@ -238,45 +246,47 @@ func (dr *DashboardServiceImpl) findDashboardsZanzanaList(ctx context.Context, q
ctx, span := tracer.Start(ctx, "dashboards.service.findDashboardsZanzanaList")
defer span.End()
resourceUIDs, err := dr.listUserResources(ctx, query)
if err != nil {
return nil, err
}
if len(resourceUIDs) == 0 {
return []dashboards.DashboardSearchProjection{}, nil
}
var result []dashboards.DashboardSearchProjection
query.DashboardUIDs = resourceUIDs
query.SkipAccessControlFilter = true
return dr.dashboardStore.FindDashboards(ctx, &query)
}
func (dr *DashboardServiceImpl) listUserResources(ctx context.Context, query dashboards.FindPersistedDashboardsQuery) ([]string, error) {
tasks := make([]func() ([]string, error), 0)
var resourceTypes []string
// For some search types we need dashboards or folders only
switch query.Type {
case searchstore.TypeDashboard:
resourceTypes = []string{zanzana.TypeDashboard}
case searchstore.TypeFolder, searchstore.TypeAlertFolder:
resourceTypes = []string{zanzana.TypeFolder}
default:
resourceTypes = []string{zanzana.TypeDashboard, zanzana.TypeFolder}
}
for _, resourceType := range resourceTypes {
tasks = append(tasks, func() ([]string, error) {
return dr.listAllowedResources(ctx, query, resourceType)
})
}
uids, err := runBatch(tasks)
allowedFolders, err := dr.listAllowedResources(ctx, query, zanzana.TypeFolder)
if err != nil {
return nil, err
}
return uids, nil
if len(allowedFolders) > 0 {
// Find dashboards in folders that user has access to
query.SkipAccessControlFilter = true
query.FolderUIDs = allowedFolders
result, err = dr.dashboardStore.FindDashboards(ctx, &query)
if err != nil {
return nil, err
}
}
// skip if limit reached
rest := query.Limit - int64(len(result))
if rest <= 0 {
return result, nil
}
// Run second query to find dashboards with direct permission assignments
allowedDashboards, err := dr.listAllowedResources(ctx, query, zanzana.TypeDashboard)
if err != nil {
return nil, err
}
if len(allowedDashboards) > 0 {
query.FolderUIDs = []string{}
query.DashboardUIDs = allowedDashboards
query.Limit = rest
dashboardRes, err := dr.dashboardStore.FindDashboards(ctx, &query)
if err != nil {
return nil, err
}
result = append(result, dashboardRes...)
}
return result, err
}
func (dr *DashboardServiceImpl) listAllowedResources(ctx context.Context, query dashboards.FindPersistedDashboardsQuery, resourceType string) ([]string, error) {
@@ -307,36 +317,3 @@ func (dr *DashboardServiceImpl) listAllowedResources(ctx context.Context, query
return resourceUIDs, nil
}
func runBatch(tasks []func() ([]string, error)) ([]string, error) {
var wg sync.WaitGroup
tasksNum := len(tasks)
resChan := make(chan []string, tasksNum)
errChan := make(chan error, tasksNum)
for _, task := range tasks {
wg.Add(1)
go func() {
defer wg.Done()
res, err := task()
resChan <- res
errChan <- err
}()
}
wg.Wait()
close(resChan)
close(errChan)
for err := range errChan {
if err != nil {
return nil, err
}
}
result := make([]string, 0)
for res := range resChan {
result = append(result, res...)
}
return result, nil
}
+2 -8
View File
@@ -1255,10 +1255,11 @@ var (
},
{
Name: "dashboardRestore",
Description: "Enables deleted dashboard restore feature (backend only)",
Description: "Enables deleted dashboard restore feature",
Stage: FeatureStageExperimental,
Owner: grafanaSearchAndStorageSquad,
HideFromAdminPage: true,
Expression: "false", // enabled by default
},
{
Name: "datasourceProxyDisableRBAC",
@@ -1367,13 +1368,6 @@ var (
Owner: grafanaAlertingSquad,
RequiresRestart: true,
},
{
Name: "dashboardRestoreUI",
Description: "Enables the frontend to be able to restore a recently deleted dashboard",
Stage: FeatureStageExperimental,
Owner: grafanaFrontendPlatformSquad,
Expression: "false", // enabled by default
},
{
Name: "cloudWatchRoundUpEndTime",
Description: "Round up end time for metric queries to the next minute to avoid missing data",
-1
View File
@@ -179,7 +179,6 @@ failWrongDSUID,experimental,@grafana/plugins-platform-backend,false,false,false
zanzana,experimental,@grafana/identity-access-team,false,false,false
passScopeToDashboardApi,experimental,@grafana/dashboards-squad,false,false,false
alertingApiServer,experimental,@grafana/alerting-squad,false,true,false
dashboardRestoreUI,experimental,@grafana/grafana-frontend-platform,false,false,false
cloudWatchRoundUpEndTime,GA,@grafana/aws-datasources,false,false,false
cloudwatchMetricInsightsCrossAccount,preview,@grafana/aws-datasources,false,false,true
prometheusAzureOverrideAudience,deprecated,@grafana/partner-datasources,false,false,false
1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
179 zanzana experimental @grafana/identity-access-team false false false
180 passScopeToDashboardApi experimental @grafana/dashboards-squad false false false
181 alertingApiServer experimental @grafana/alerting-squad false true false
dashboardRestoreUI experimental @grafana/grafana-frontend-platform false false false
182 cloudWatchRoundUpEndTime GA @grafana/aws-datasources false false false
183 cloudwatchMetricInsightsCrossAccount preview @grafana/aws-datasources false false true
184 prometheusAzureOverrideAudience deprecated @grafana/partner-datasources false false false
+1 -5
View File
@@ -668,7 +668,7 @@ const (
FlagNotificationBanner = "notificationBanner"
// FlagDashboardRestore
// Enables deleted dashboard restore feature (backend only)
// Enables deleted dashboard restore feature
FlagDashboardRestore = "dashboardRestore"
// FlagDatasourceProxyDisableRBAC
@@ -727,10 +727,6 @@ const (
// Register Alerting APIs with the K8s API server
FlagAlertingApiServer = "alertingApiServer"
// FlagDashboardRestoreUI
// Enables the frontend to be able to restore a recently deleted dashboard
FlagDashboardRestoreUI = "dashboardRestoreUI"
// FlagCloudWatchRoundUpEndTime
// Round up end time for metric queries to the next minute to avoid missing data
FlagCloudWatchRoundUpEndTime = "cloudWatchRoundUpEndTime"
+21 -5
View File
@@ -808,17 +808,18 @@
{
"metadata": {
"name": "dashboardRestore",
"resourceVersion": "1719321877748",
"resourceVersion": "1728397491294",
"creationTimestamp": "2024-05-16T17:36:26Z",
"annotations": {
"grafana.app/updatedTimestamp": "2024-06-25 13:24:37.748284 +0000 UTC"
"grafana.app/updatedTimestamp": "2024-10-08 14:24:51.294668 +0000 UTC"
}
},
"spec": {
"description": "Enables deleted dashboard restore feature (backend only)",
"description": "Enables deleted dashboard restore feature",
"stage": "experimental",
"codeowner": "@grafana/search-and-storage",
"hideFromAdminPage": true
"hideFromAdminPage": true,
"expression": "false"
}
},
{
@@ -826,6 +827,7 @@
"name": "dashboardRestoreUI",
"resourceVersion": "1720021873452",
"creationTimestamp": "2024-06-25T14:43:13Z",
"deletionTimestamp": "2024-10-08T14:24:51Z",
"annotations": {
"grafana.app/updatedTimestamp": "2024-07-03 15:51:13.452477 +0000 UTC"
}
@@ -3087,6 +3089,20 @@
"codeowner": "@grafana/identity-access-team"
}
},
{
"metadata": {
"name": "unifiedStorageSearch",
"resourceVersion": "1726771421439",
"creationTimestamp": "2024-09-19T18:43:41Z"
},
"spec": {
"description": "Enable unified storage search",
"stage": "experimental",
"codeowner": "@grafana/search-and-storage",
"hideFromAdminPage": true,
"hideFromDocs": true
}
},
{
"metadata": {
"name": "vizActions",
@@ -3141,4 +3157,4 @@
}
}
]
}
}
+27 -1
View File
@@ -260,6 +260,7 @@ func (s *Service) Get(ctx context.Context, q *folder.GetFolderQuery) (*folder.Fo
if !s.features.IsEnabled(ctx, featuremgmt.FlagNestedFolders) {
dashFolder.Fullpath = dashFolder.Title
dashFolder.FullpathUIDs = dashFolder.UID
return dashFolder, nil
}
@@ -282,7 +283,8 @@ func (s *Service) Get(ctx context.Context, q *folder.GetFolderQuery) (*folder.Fo
f.Version = dashFolder.Version
if !s.features.IsEnabled(ctx, featuremgmt.FlagNestedFolders) {
f.Fullpath = f.Title // set full path to the folder title (unescaped)
f.Fullpath = f.Title // set full path to the folder title (unescaped)
f.FullpathUIDs = f.UID // set full path to the folder UID
}
return f, err
@@ -671,6 +673,30 @@ func (s *Service) Create(ctx context.Context, cmd *folder.CreateFolderCommand) (
return nil, err
}
if s.features.IsEnabled(ctx, featuremgmt.FlagKubernetesFolders) {
if f.ParentUID == "" {
return f, nil
}
// Fetch the parent since the permissions for fetching the newly created folder
// are not yet present for the user--this requires a call to ClearUserPermissionCache
parent, err := s.Get(ctx, &folder.GetFolderQuery{
UID: &f.ParentUID,
OrgID: f.OrgID,
WithFullpath: true,
WithFullpathUIDs: true,
SignedInUser: user,
})
if err != nil {
return nil, err
}
// #TODO revisit setting permissions so that we can centralise the logic for escaping slashes in titles
// Escape forward slashes in the title
title := strings.Replace(f.Title, "/", "\\/", -1)
f.Fullpath = title + "/" + parent.Fullpath
f.FullpathUIDs = f.UID + "/" + parent.FullpathUIDs
}
return f, nil
}
+31 -14
View File
@@ -501,7 +501,7 @@ func TestIntegrationNestedFolderService(t *testing.T) {
lps, err := librarypanels.ProvideService(cfg, db, routeRegister, elementService, serviceWithFlagOn)
require.NoError(t, err)
ancestors := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "getDescendantCountsOn", createCmd)
ancestors := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "getDescendantCountsOn", createCmd, true)
parent, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestors[0].UID)
require.NoError(t, err)
@@ -584,7 +584,7 @@ func TestIntegrationNestedFolderService(t *testing.T) {
lps, err := librarypanels.ProvideService(cfg, db, routeRegister, elementService, serviceWithFlagOff)
require.NoError(t, err)
ancestors := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "getDescendantCountsOff", createCmd)
ancestors := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "getDescendantCountsOff", createCmd, true)
parent, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestors[0].UID)
require.NoError(t, err)
@@ -725,7 +725,7 @@ func TestIntegrationNestedFolderService(t *testing.T) {
alertStore, err := ngstore.ProvideDBStore(cfg, tc.featuresFlag, db, tc.service, dashSrv, ac)
require.NoError(t, err)
ancestors := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, tc.depth, tc.prefix, createCmd)
ancestors := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, tc.depth, tc.prefix, createCmd, true)
parent, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestors[0].UID)
require.NoError(t, err)
@@ -1536,8 +1536,8 @@ func TestIntegrationNestedFolderSharedWithMe(t *testing.T) {
t.Run("Should get folders shared with given user", func(t *testing.T) {
depth := 3
ancestorFoldersWithPermissions := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "withPermissions", createCmd)
ancestorFoldersWithoutPermissions := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "withoutPermissions", createCmd)
ancestorFoldersWithPermissions := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "withPermissions", createCmd, true)
ancestorFoldersWithoutPermissions := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "withoutPermissions", createCmd, true)
parent, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestorFoldersWithoutPermissions[0].UID)
require.NoError(t, err)
@@ -1661,8 +1661,8 @@ func TestIntegrationNestedFolderSharedWithMe(t *testing.T) {
// tree2-folder-0
// └──tree2-folder-1
// └──tree2-folder-2
tree1 := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "tree1-", createCmd)
tree2 := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "tree2-", createCmd)
tree1 := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "tree1-", createCmd, true)
tree2 := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "tree2-", createCmd, true)
signedInUser.Permissions[orgID][dashboards.ActionFoldersRead] = []string{
// Add permission to tree1-folder-0
@@ -1928,14 +1928,16 @@ func TestFolderServiceGetFolder(t *testing.T) {
}
depth := 3
folders := CreateSubtreeInStore(t, folderSvcOn.store, &folderSvcOn, depth, "get/folder-", createCmd)
folders := CreateSubtreeInStore(t, folderSvcOn.store, &folderSvcOn, depth, "get/folder-", createCmd, false)
f := folders[1]
testCases := []struct {
name string
svc *Service
WithFullpath bool
expectedFullpath string
name string
svc *Service
WithFullpath bool
WithFullpathUIDs bool
expectedFullpath string
expectedFullpathUIDs string
}{
{
name: "when flag is off",
@@ -1954,6 +1956,18 @@ func TestFolderServiceGetFolder(t *testing.T) {
WithFullpath: true,
expectedFullpath: "get\\/folder-folder-0/get\\/folder-folder-1",
},
{
name: "when flag is on and WithFullpathUIDs is false",
svc: &folderSvcOn,
WithFullpathUIDs: false,
expectedFullpathUIDs: "",
},
{
name: "when flag is on and WithFullpathUIDs is true",
svc: &folderSvcOn,
WithFullpathUIDs: true,
expectedFullpathUIDs: "uidfor-0/uidfor-1",
},
}
for _, tc := range testCases {
@@ -2021,7 +2035,7 @@ func TestFolderServiceGetFolders(t *testing.T) {
})
prefix := "getfolders/ff/off"
folders := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOff, 5, prefix, createCmd)
folders := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOff, 5, prefix, createCmd, true)
f := folders[rand.Intn(len(folders))]
t.Run("when flag is off", func(t *testing.T) {
@@ -2510,7 +2524,7 @@ func TestSupportBundle(t *testing.T) {
}
}
func CreateSubtreeInStore(t *testing.T, store folder.Store, service *Service, depth int, prefix string, cmd folder.CreateFolderCommand) []*folder.Folder {
func CreateSubtreeInStore(t *testing.T, store folder.Store, service *Service, depth int, prefix string, cmd folder.CreateFolderCommand, randomUID bool) []*folder.Folder {
t.Helper()
folders := make([]*folder.Folder, 0, depth)
@@ -2518,6 +2532,9 @@ func CreateSubtreeInStore(t *testing.T, store folder.Store, service *Service, de
title := fmt.Sprintf("%sfolder-%d", prefix, i)
cmd.Title = title
cmd.UID = util.GenerateShortUID()
if !randomUID {
cmd.UID = fmt.Sprintf("uidfor-%d", i)
}
cmd.OrgID = orgID
cmd.SignedInUser = &user.SignedInUser{OrgID: orgID, Permissions: map[int64]map[string][]string{orgID: {dashboards.ActionFoldersCreate: {dashboards.ScopeFoldersAll}}}}
+5 -1
View File
@@ -201,8 +201,11 @@ func (ss *FolderStoreImpl) Get(ctx context.Context, q folder.GetFolderQuery) (*f
if q.WithFullpath {
s.WriteString(fmt.Sprintf(`, %s AS fullpath`, getFullpathSQL(ss.db.GetDialect())))
}
if q.WithFullpathUIDs {
s.WriteString(fmt.Sprintf(`, %s AS fullpath_uids`, getFullapathUIDsSQL(ss.db.GetDialect())))
}
s.WriteString(" FROM folder f0")
if q.WithFullpath {
if q.WithFullpath || q.WithFullpathUIDs {
s.WriteString(getFullpathJoinsSQL())
}
switch {
@@ -241,6 +244,7 @@ func (ss *FolderStoreImpl) Get(ctx context.Context, q folder.GetFolderQuery) (*f
})
foldr.Fullpath = strings.TrimLeft(foldr.Fullpath, "/")
foldr.FullpathUIDs = strings.TrimLeft(foldr.FullpathUIDs, "/")
return foldr.WithURL(), err
}
@@ -485,6 +485,24 @@ func TestIntegrationGet(t *testing.T) {
assert.NotEmpty(t, ff.Updated)
assert.NotEmpty(t, ff.URL)
})
t.Run("get folder withFullpathUIDs should set fullpathUIDs as expected", func(t *testing.T) {
ff, err := folderStore.Get(context.Background(), folder.GetFolderQuery{
UID: &subfolderWithSameName.UID,
OrgID: orgID,
WithFullpathUIDs: true,
})
require.NoError(t, err)
assert.Equal(t, subfolderWithSameName.UID, ff.UID)
assert.Equal(t, subfolderWithSameName.OrgID, ff.OrgID)
assert.Equal(t, subfolderWithSameName.Title, ff.Title)
assert.Equal(t, subfolderWithSameName.Description, ff.Description)
assert.Equal(t, path.Join(f.UID, subfolderWithSameName.UID), ff.FullpathUIDs)
assert.Equal(t, f.UID, ff.ParentUID)
assert.NotEmpty(t, ff.Created)
assert.NotEmpty(t, ff.Updated)
assert.NotEmpty(t, ff.URL)
})
}
func TestIntegrationGetParents(t *testing.T) {
+6 -5
View File
@@ -148,11 +148,12 @@ type DeleteFolderCommand struct {
type GetFolderQuery struct {
UID *string
// Deprecated: use FolderUID instead
ID *int64
Title *string
ParentUID *string
OrgID int64
WithFullpath bool
ID *int64
Title *string
ParentUID *string
OrgID int64
WithFullpath bool
WithFullpathUIDs bool
SignedInUser identity.Requester `json:"-"`
}
+6
View File
@@ -27,6 +27,7 @@ type UserAuth struct {
type ExternalUserInfo struct {
OAuthToken *oauth2.Token
SAMLSession *SAMLSession
AuthModule string
AuthId string
UserId int64
@@ -40,6 +41,11 @@ type ExternalUserInfo struct {
SkipTeamSync bool
}
type SAMLSession struct {
NameID string
SessionIndex string
}
func (e *ExternalUserInfo) String() string {
isGrafanaAdmin := "nil"
if e.IsGrafanaAdmin != nil {

Some files were not shown because too many files have changed in this diff Show More