🌊 Streams: Add streams feature privilege (#218966)

This PR adds a new feature for streams to control whether the UI and API
is available.

Changes:
* Add the feature with two privileges (`show` and `manage_assets`)
* Can be configured with the classic `none`/`read`/`all` so it's
automatically aligned with serverless editor/viewer permissions
* None also means the app is not shown - to do this, the existing
`status$` observable also looks for at least the `streams.show`
capability
* Only guards changes to the linked dashboards - changes to the
Elasticsearch level are still delegated to the Elasticsearch-level
permissions of the user
* This happens on the UI level (disabled button and dashboard selection
on the dashboard page)
* and on the API level (all endpoints that can change linked dashboards
require the permission)


# Questions

* Not sure about the name `manage_assets` - maybe it should be something
else
* Not sure about how the queries stuff should work - @kdelemme anything
we should do in this area?

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Joe Reuter 2025-04-28 11:50:05 +02:00 committed by GitHub
parent 47736b2129
commit b1d85aa6a8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
40 changed files with 310 additions and 265 deletions

View file

@ -46891,7 +46891,7 @@
},
"/api/streams": {
"get": {
"description": "Fetches list of all streams",
"description": "Fetches list of all streams<br/><br/>[Required authorization] Route required privileges: read_stream.",
"operationId": "get-streams",
"parameters": [],
"requestBody": {
@ -46928,7 +46928,7 @@
},
"/api/streams/_disable": {
"post": {
"description": "Disables wired streams and deletes all existing stream definitions. The data of wired streams is deleted, but the data of classic streams is preserved.",
"description": "Disables wired streams and deletes all existing stream definitions. The data of wired streams is deleted, but the data of classic streams is preserved.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "post-streams-disable",
"parameters": [
{
@ -46976,7 +46976,7 @@
},
"/api/streams/_enable": {
"post": {
"description": "Enables wired streams",
"description": "Enables wired streams<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "post-streams-enable",
"parameters": [
{
@ -47024,7 +47024,7 @@
},
"/api/streams/_resync": {
"post": {
"description": "Resyncs all streams, making sure that Elasticsearch assets are up to date",
"description": "Resyncs all streams, making sure that Elasticsearch assets are up to date<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "post-streams-resync",
"parameters": [
{
@ -47072,7 +47072,7 @@
},
"/api/streams/{name}": {
"delete": {
"description": "Deletes a stream definition and the underlying data stream",
"description": "Deletes a stream definition and the underlying data stream<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "delete-streams-name",
"parameters": [
{
@ -47126,7 +47126,7 @@
"x-state": "Technical Preview"
},
"get": {
"description": "Fetches a stream definition and associated dashboards",
"description": "Fetches a stream definition and associated dashboards<br/><br/>[Required authorization] Route required privileges: read_stream.",
"operationId": "get-streams-name",
"parameters": [
{
@ -47170,7 +47170,7 @@
"x-state": "Technical Preview"
},
"put": {
"description": "Creates or updates a stream definition. Classic streams can not be created through this API, only updated",
"description": "Creates or updates a stream definition. Classic streams can not be created through this API, only updated<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "put-streams-name",
"parameters": [
{
@ -50598,7 +50598,7 @@
},
"/api/streams/{name}/_fork": {
"post": {
"description": "Forks a wired stream and creates a child stream",
"description": "Forks a wired stream and creates a child stream<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "post-streams-name-fork",
"parameters": [
{
@ -50783,7 +50783,7 @@
},
"/api/streams/{name}/_group": {
"get": {
"description": "Fetches the group settings of a group stream definition",
"description": "Fetches the group settings of a group stream definition<br/><br/>[Required authorization] Route required privileges: read_stream.",
"operationId": "get-streams-name-group",
"parameters": [
{
@ -50827,7 +50827,7 @@
"x-state": "Technical Preview"
},
"put": {
"description": "Upserts the group settings of a group stream definition",
"description": "Upserts the group settings of a group stream definition<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "put-streams-name-group",
"parameters": [
{
@ -50893,7 +50893,7 @@
},
"/api/streams/{name}/_ingest": {
"get": {
"description": "Fetches the ingest settings of an ingest stream definition",
"description": "Fetches the ingest settings of an ingest stream definition<br/><br/>[Required authorization] Route required privileges: read_stream.",
"operationId": "get-streams-name-ingest",
"parameters": [
{
@ -50937,7 +50937,7 @@
"x-state": "Technical Preview"
},
"put": {
"description": "Upserts the ingest settings of an ingest stream definition",
"description": "Upserts the ingest settings of an ingest stream definition<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "put-streams-name-ingest",
"parameters": [
{
@ -54114,7 +54114,7 @@
},
"/api/streams/{name}/content/export": {
"post": {
"description": "Exports the content associated to a stream.",
"description": "Exports the content associated to a stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "post-streams-name-content-export",
"parameters": [
{
@ -54221,7 +54221,7 @@
},
"/api/streams/{name}/content/import": {
"post": {
"description": "Links content objects to a stream.",
"description": "Links content objects to a stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "post-streams-name-content-import",
"parameters": [
{
@ -54272,7 +54272,7 @@
},
"/api/streams/{name}/dashboards": {
"get": {
"description": "Fetches all dashboards linked to a stream that are visible to the current user in the current space.",
"description": "Fetches all dashboards linked to a stream that are visible to the current user in the current space.<br/><br/>[Required authorization] Route required privileges: read_stream.",
"operationId": "get-streams-name-dashboards",
"parameters": [
{
@ -54318,7 +54318,7 @@
},
"/api/streams/{name}/dashboards/_bulk": {
"post": {
"description": "Bulk update dashboards linked to a stream. Can link new dashboards and delete existing ones.",
"description": "Bulk update dashboards linked to a stream. Can link new dashboards and delete existing ones.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "post-streams-name-dashboards-bulk",
"parameters": [
{
@ -54414,7 +54414,7 @@
},
"/api/streams/{name}/dashboards/{dashboardId}": {
"delete": {
"description": "Unlinks a dashboard from a stream. Noop if the dashboard is not linked to the stream.",
"description": "Unlinks a dashboard from a stream. Noop if the dashboard is not linked to the stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "delete-streams-name-dashboards-dashboardid",
"parameters": [
{
@ -54476,7 +54476,7 @@
"x-state": "Technical Preview"
},
"put": {
"description": "Links a dashboard to a stream. Noop if the dashboard is already linked to the stream.",
"description": "Links a dashboard to a stream. Noop if the dashboard is already linked to the stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "put-streams-name-dashboards-dashboardid",
"parameters": [
{
@ -54540,7 +54540,7 @@
},
"/api/streams/{name}/queries": {
"get": {
"description": "Fetches all queries linked to a stream that are visible to the current user in the current space.",
"description": "Fetches all queries linked to a stream that are visible to the current user in the current space.<br/><br/>[Required authorization] Route required privileges: read_stream.",
"operationId": "get-streams-name-queries",
"parameters": [
{
@ -54586,7 +54586,7 @@
},
"/api/streams/{name}/queries/_bulk": {
"post": {
"description": "Bulk update queries of a stream. Can add new queries and delete existing ones.",
"description": "Bulk update queries of a stream. Can add new queries and delete existing ones.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "post-streams-name-queries-bulk",
"parameters": [
{
@ -54712,7 +54712,7 @@
},
"/api/streams/{name}/queries/{queryId}": {
"delete": {
"description": "Remove a query from a stream. Noop if the query is not found on the stream.",
"description": "Remove a query from a stream. Noop if the query is not found on the stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "delete-streams-name-queries-queryid",
"parameters": [
{
@ -54774,7 +54774,7 @@
"x-state": "Technical Preview"
},
"put": {
"description": "Adds a query to a stream. Noop if the query is already present on the stream.",
"description": "Adds a query to a stream. Noop if the query is already present on the stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "put-streams-name-queries-queryid",
"parameters": [
{
@ -54847,7 +54847,7 @@
},
"/api/streams/{name}/significant_events": {
"get": {
"description": "Read the significant events",
"description": "Read the significant events<br/><br/>[Required authorization] Route required privileges: read_stream.",
"operationId": "get-streams-name-significant-events",
"parameters": [
{

View file

@ -46482,7 +46482,7 @@
},
"/api/streams": {
"get": {
"description": "Fetches list of all streams",
"description": "Fetches list of all streams<br/><br/>[Required authorization] Route required privileges: read_stream.",
"operationId": "get-streams",
"parameters": [],
"requestBody": {
@ -46519,7 +46519,7 @@
},
"/api/streams/_disable": {
"post": {
"description": "Disables wired streams and deletes all existing stream definitions. The data of wired streams is deleted, but the data of classic streams is preserved.",
"description": "Disables wired streams and deletes all existing stream definitions. The data of wired streams is deleted, but the data of classic streams is preserved.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "post-streams-disable",
"parameters": [
{
@ -46567,7 +46567,7 @@
},
"/api/streams/_enable": {
"post": {
"description": "Enables wired streams",
"description": "Enables wired streams<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "post-streams-enable",
"parameters": [
{
@ -46615,7 +46615,7 @@
},
"/api/streams/_resync": {
"post": {
"description": "Resyncs all streams, making sure that Elasticsearch assets are up to date",
"description": "Resyncs all streams, making sure that Elasticsearch assets are up to date<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "post-streams-resync",
"parameters": [
{
@ -46663,7 +46663,7 @@
},
"/api/streams/{name}": {
"delete": {
"description": "Deletes a stream definition and the underlying data stream",
"description": "Deletes a stream definition and the underlying data stream<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "delete-streams-name",
"parameters": [
{
@ -46717,7 +46717,7 @@
"x-state": "Technical Preview"
},
"get": {
"description": "Fetches a stream definition and associated dashboards",
"description": "Fetches a stream definition and associated dashboards<br/><br/>[Required authorization] Route required privileges: read_stream.",
"operationId": "get-streams-name",
"parameters": [
{
@ -46761,7 +46761,7 @@
"x-state": "Technical Preview"
},
"put": {
"description": "Creates or updates a stream definition. Classic streams can not be created through this API, only updated",
"description": "Creates or updates a stream definition. Classic streams can not be created through this API, only updated<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "put-streams-name",
"parameters": [
{
@ -50189,7 +50189,7 @@
},
"/api/streams/{name}/_fork": {
"post": {
"description": "Forks a wired stream and creates a child stream",
"description": "Forks a wired stream and creates a child stream<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "post-streams-name-fork",
"parameters": [
{
@ -50374,7 +50374,7 @@
},
"/api/streams/{name}/_group": {
"get": {
"description": "Fetches the group settings of a group stream definition",
"description": "Fetches the group settings of a group stream definition<br/><br/>[Required authorization] Route required privileges: read_stream.",
"operationId": "get-streams-name-group",
"parameters": [
{
@ -50418,7 +50418,7 @@
"x-state": "Technical Preview"
},
"put": {
"description": "Upserts the group settings of a group stream definition",
"description": "Upserts the group settings of a group stream definition<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "put-streams-name-group",
"parameters": [
{
@ -50484,7 +50484,7 @@
},
"/api/streams/{name}/_ingest": {
"get": {
"description": "Fetches the ingest settings of an ingest stream definition",
"description": "Fetches the ingest settings of an ingest stream definition<br/><br/>[Required authorization] Route required privileges: read_stream.",
"operationId": "get-streams-name-ingest",
"parameters": [
{
@ -50528,7 +50528,7 @@
"x-state": "Technical Preview"
},
"put": {
"description": "Upserts the ingest settings of an ingest stream definition",
"description": "Upserts the ingest settings of an ingest stream definition<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "put-streams-name-ingest",
"parameters": [
{
@ -53705,7 +53705,7 @@
},
"/api/streams/{name}/content/export": {
"post": {
"description": "Exports the content associated to a stream.",
"description": "Exports the content associated to a stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "post-streams-name-content-export",
"parameters": [
{
@ -53812,7 +53812,7 @@
},
"/api/streams/{name}/content/import": {
"post": {
"description": "Links content objects to a stream.",
"description": "Links content objects to a stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "post-streams-name-content-import",
"parameters": [
{
@ -53863,7 +53863,7 @@
},
"/api/streams/{name}/dashboards": {
"get": {
"description": "Fetches all dashboards linked to a stream that are visible to the current user in the current space.",
"description": "Fetches all dashboards linked to a stream that are visible to the current user in the current space.<br/><br/>[Required authorization] Route required privileges: read_stream.",
"operationId": "get-streams-name-dashboards",
"parameters": [
{
@ -53909,7 +53909,7 @@
},
"/api/streams/{name}/dashboards/_bulk": {
"post": {
"description": "Bulk update dashboards linked to a stream. Can link new dashboards and delete existing ones.",
"description": "Bulk update dashboards linked to a stream. Can link new dashboards and delete existing ones.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "post-streams-name-dashboards-bulk",
"parameters": [
{
@ -54005,7 +54005,7 @@
},
"/api/streams/{name}/dashboards/{dashboardId}": {
"delete": {
"description": "Unlinks a dashboard from a stream. Noop if the dashboard is not linked to the stream.",
"description": "Unlinks a dashboard from a stream. Noop if the dashboard is not linked to the stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "delete-streams-name-dashboards-dashboardid",
"parameters": [
{
@ -54067,7 +54067,7 @@
"x-state": "Technical Preview"
},
"put": {
"description": "Links a dashboard to a stream. Noop if the dashboard is already linked to the stream.",
"description": "Links a dashboard to a stream. Noop if the dashboard is already linked to the stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "put-streams-name-dashboards-dashboardid",
"parameters": [
{
@ -54131,7 +54131,7 @@
},
"/api/streams/{name}/queries": {
"get": {
"description": "Fetches all queries linked to a stream that are visible to the current user in the current space.",
"description": "Fetches all queries linked to a stream that are visible to the current user in the current space.<br/><br/>[Required authorization] Route required privileges: read_stream.",
"operationId": "get-streams-name-queries",
"parameters": [
{
@ -54177,7 +54177,7 @@
},
"/api/streams/{name}/queries/_bulk": {
"post": {
"description": "Bulk update queries of a stream. Can add new queries and delete existing ones.",
"description": "Bulk update queries of a stream. Can add new queries and delete existing ones.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "post-streams-name-queries-bulk",
"parameters": [
{
@ -54303,7 +54303,7 @@
},
"/api/streams/{name}/queries/{queryId}": {
"delete": {
"description": "Remove a query from a stream. Noop if the query is not found on the stream.",
"description": "Remove a query from a stream. Noop if the query is not found on the stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "delete-streams-name-queries-queryid",
"parameters": [
{
@ -54365,7 +54365,7 @@
"x-state": "Technical Preview"
},
"put": {
"description": "Adds a query to a stream. Noop if the query is already present on the stream.",
"description": "Adds a query to a stream. Noop if the query is already present on the stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.",
"operationId": "put-streams-name-queries-queryid",
"parameters": [
{
@ -54438,7 +54438,7 @@
},
"/api/streams/{name}/significant_events": {
"get": {
"description": "Read the significant events",
"description": "Read the significant events<br/><br/>[Required authorization] Route required privileges: read_stream.",
"operationId": "get-streams-name-significant-events",
"parameters": [
{

View file

@ -44091,7 +44091,7 @@ paths:
- system
/api/streams:
get:
description: Fetches list of all streams
description: 'Fetches list of all streams<br/><br/>[Required authorization] Route required privileges: read_stream.'
operationId: get-streams
parameters: []
requestBody:
@ -44113,7 +44113,7 @@ paths:
x-state: Technical Preview
/api/streams/_disable:
post:
description: Disables wired streams and deletes all existing stream definitions. The data of wired streams is deleted, but the data of classic streams is preserved.
description: 'Disables wired streams and deletes all existing stream definitions. The data of wired streams is deleted, but the data of classic streams is preserved.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: post-streams-disable
parameters:
- description: A required header to protect against CSRF attacks
@ -44142,7 +44142,7 @@ paths:
x-state: Technical Preview
/api/streams/_enable:
post:
description: Enables wired streams
description: 'Enables wired streams<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: post-streams-enable
parameters:
- description: A required header to protect against CSRF attacks
@ -44171,7 +44171,7 @@ paths:
x-state: Technical Preview
/api/streams/_resync:
post:
description: Resyncs all streams, making sure that Elasticsearch assets are up to date
description: 'Resyncs all streams, making sure that Elasticsearch assets are up to date<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: post-streams-resync
parameters:
- description: A required header to protect against CSRF attacks
@ -44200,7 +44200,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}:
delete:
description: Deletes a stream definition and the underlying data stream
description: 'Deletes a stream definition and the underlying data stream<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: delete-streams-name
parameters:
- description: A required header to protect against CSRF attacks
@ -44233,7 +44233,7 @@ paths:
- streams
x-state: Technical Preview
get:
description: Fetches a stream definition and associated dashboards
description: 'Fetches a stream definition and associated dashboards<br/><br/>[Required authorization] Route required privileges: read_stream.'
operationId: get-streams-name
parameters:
- in: path
@ -44259,7 +44259,7 @@ paths:
- streams
x-state: Technical Preview
put:
description: Creates or updates a stream definition. Classic streams can not be created through this API, only updated
description: 'Creates or updates a stream definition. Classic streams can not be created through this API, only updated<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: put-streams-name
parameters:
- description: A required header to protect against CSRF attacks
@ -46380,7 +46380,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/_fork:
post:
description: Forks a wired stream and creates a child stream
description: 'Forks a wired stream and creates a child stream<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: post-streams-name-fork
parameters:
- description: A required header to protect against CSRF attacks
@ -46498,7 +46498,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/_group:
get:
description: Fetches the group settings of a group stream definition
description: 'Fetches the group settings of a group stream definition<br/><br/>[Required authorization] Route required privileges: read_stream.'
operationId: get-streams-name-group
parameters:
- in: path
@ -46524,7 +46524,7 @@ paths:
- streams
x-state: Technical Preview
put:
description: Upserts the group settings of a group stream definition
description: 'Upserts the group settings of a group stream definition<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: put-streams-name-group
parameters:
- description: A required header to protect against CSRF attacks
@ -46568,7 +46568,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/_ingest:
get:
description: Fetches the ingest settings of an ingest stream definition
description: 'Fetches the ingest settings of an ingest stream definition<br/><br/>[Required authorization] Route required privileges: read_stream.'
operationId: get-streams-name-ingest
parameters:
- in: path
@ -46594,7 +46594,7 @@ paths:
- streams
x-state: Technical Preview
put:
description: Upserts the ingest settings of an ingest stream definition
description: 'Upserts the ingest settings of an ingest stream definition<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: put-streams-name-ingest
parameters:
- description: A required header to protect against CSRF attacks
@ -48564,7 +48564,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/content/export:
post:
description: Exports the content associated to a stream.
description: 'Exports the content associated to a stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: post-streams-name-content-export
parameters:
- description: A required header to protect against CSRF attacks
@ -48634,7 +48634,7 @@ paths:
- streams
/api/streams/{name}/content/import:
post:
description: Links content objects to a stream.
description: 'Links content objects to a stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: post-streams-name-content-import
parameters:
- description: A required header to protect against CSRF attacks
@ -48668,7 +48668,7 @@ paths:
- streams
/api/streams/{name}/dashboards:
get:
description: Fetches all dashboards linked to a stream that are visible to the current user in the current space.
description: 'Fetches all dashboards linked to a stream that are visible to the current user in the current space.<br/><br/>[Required authorization] Route required privileges: read_stream.'
operationId: get-streams-name-dashboards
parameters:
- in: path
@ -48695,7 +48695,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/dashboards/_bulk:
post:
description: Bulk update dashboards linked to a stream. Can link new dashboards and delete existing ones.
description: 'Bulk update dashboards linked to a stream. Can link new dashboards and delete existing ones.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: post-streams-name-dashboards-bulk
parameters:
- description: A required header to protect against CSRF attacks
@ -48756,7 +48756,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/dashboards/{dashboardId}:
delete:
description: Unlinks a dashboard from a stream. Noop if the dashboard is not linked to the stream.
description: 'Unlinks a dashboard from a stream. Noop if the dashboard is not linked to the stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: delete-streams-name-dashboards-dashboardid
parameters:
- description: A required header to protect against CSRF attacks
@ -48794,7 +48794,7 @@ paths:
- streams
x-state: Technical Preview
put:
description: Links a dashboard to a stream. Noop if the dashboard is already linked to the stream.
description: 'Links a dashboard to a stream. Noop if the dashboard is already linked to the stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: put-streams-name-dashboards-dashboardid
parameters:
- description: A required header to protect against CSRF attacks
@ -48833,7 +48833,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/queries:
get:
description: Fetches all queries linked to a stream that are visible to the current user in the current space.
description: 'Fetches all queries linked to a stream that are visible to the current user in the current space.<br/><br/>[Required authorization] Route required privileges: read_stream.'
operationId: get-streams-name-queries
parameters:
- in: path
@ -48860,7 +48860,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/queries/_bulk:
post:
description: Bulk update queries of a stream. Can add new queries and delete existing ones.
description: 'Bulk update queries of a stream. Can add new queries and delete existing ones.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: post-streams-name-queries-bulk
parameters:
- description: A required header to protect against CSRF attacks
@ -48939,7 +48939,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/queries/{queryId}:
delete:
description: Remove a query from a stream. Noop if the query is not found on the stream.
description: 'Remove a query from a stream. Noop if the query is not found on the stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: delete-streams-name-queries-queryid
parameters:
- description: A required header to protect against CSRF attacks
@ -48977,7 +48977,7 @@ paths:
- streams
x-state: Technical Preview
put:
description: Adds a query to a stream. Noop if the query is already present on the stream.
description: 'Adds a query to a stream. Noop if the query is already present on the stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: put-streams-name-queries-queryid
parameters:
- description: A required header to protect against CSRF attacks
@ -49026,7 +49026,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/significant_events:
get:
description: Read the significant events
description: 'Read the significant events<br/><br/>[Required authorization] Route required privileges: read_stream.'
operationId: get-streams-name-significant-events
parameters:
- in: path

View file

@ -47613,7 +47613,7 @@ paths:
- system
/api/streams:
get:
description: Fetches list of all streams
description: 'Fetches list of all streams<br/><br/>[Required authorization] Route required privileges: read_stream.'
operationId: get-streams
parameters: []
requestBody:
@ -47635,7 +47635,7 @@ paths:
x-state: Technical Preview
/api/streams/_disable:
post:
description: Disables wired streams and deletes all existing stream definitions. The data of wired streams is deleted, but the data of classic streams is preserved.
description: 'Disables wired streams and deletes all existing stream definitions. The data of wired streams is deleted, but the data of classic streams is preserved.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: post-streams-disable
parameters:
- description: A required header to protect against CSRF attacks
@ -47664,7 +47664,7 @@ paths:
x-state: Technical Preview
/api/streams/_enable:
post:
description: Enables wired streams
description: 'Enables wired streams<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: post-streams-enable
parameters:
- description: A required header to protect against CSRF attacks
@ -47693,7 +47693,7 @@ paths:
x-state: Technical Preview
/api/streams/_resync:
post:
description: Resyncs all streams, making sure that Elasticsearch assets are up to date
description: 'Resyncs all streams, making sure that Elasticsearch assets are up to date<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: post-streams-resync
parameters:
- description: A required header to protect against CSRF attacks
@ -47722,7 +47722,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}:
delete:
description: Deletes a stream definition and the underlying data stream
description: 'Deletes a stream definition and the underlying data stream<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: delete-streams-name
parameters:
- description: A required header to protect against CSRF attacks
@ -47755,7 +47755,7 @@ paths:
- streams
x-state: Technical Preview
get:
description: Fetches a stream definition and associated dashboards
description: 'Fetches a stream definition and associated dashboards<br/><br/>[Required authorization] Route required privileges: read_stream.'
operationId: get-streams-name
parameters:
- in: path
@ -47781,7 +47781,7 @@ paths:
- streams
x-state: Technical Preview
put:
description: Creates or updates a stream definition. Classic streams can not be created through this API, only updated
description: 'Creates or updates a stream definition. Classic streams can not be created through this API, only updated<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: put-streams-name
parameters:
- description: A required header to protect against CSRF attacks
@ -49902,7 +49902,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/_fork:
post:
description: Forks a wired stream and creates a child stream
description: 'Forks a wired stream and creates a child stream<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: post-streams-name-fork
parameters:
- description: A required header to protect against CSRF attacks
@ -50020,7 +50020,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/_group:
get:
description: Fetches the group settings of a group stream definition
description: 'Fetches the group settings of a group stream definition<br/><br/>[Required authorization] Route required privileges: read_stream.'
operationId: get-streams-name-group
parameters:
- in: path
@ -50046,7 +50046,7 @@ paths:
- streams
x-state: Technical Preview
put:
description: Upserts the group settings of a group stream definition
description: 'Upserts the group settings of a group stream definition<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: put-streams-name-group
parameters:
- description: A required header to protect against CSRF attacks
@ -50090,7 +50090,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/_ingest:
get:
description: Fetches the ingest settings of an ingest stream definition
description: 'Fetches the ingest settings of an ingest stream definition<br/><br/>[Required authorization] Route required privileges: read_stream.'
operationId: get-streams-name-ingest
parameters:
- in: path
@ -50116,7 +50116,7 @@ paths:
- streams
x-state: Technical Preview
put:
description: Upserts the ingest settings of an ingest stream definition
description: 'Upserts the ingest settings of an ingest stream definition<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: put-streams-name-ingest
parameters:
- description: A required header to protect against CSRF attacks
@ -52086,7 +52086,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/content/export:
post:
description: Exports the content associated to a stream.
description: 'Exports the content associated to a stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: post-streams-name-content-export
parameters:
- description: A required header to protect against CSRF attacks
@ -52156,7 +52156,7 @@ paths:
- streams
/api/streams/{name}/content/import:
post:
description: Links content objects to a stream.
description: 'Links content objects to a stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: post-streams-name-content-import
parameters:
- description: A required header to protect against CSRF attacks
@ -52190,7 +52190,7 @@ paths:
- streams
/api/streams/{name}/dashboards:
get:
description: Fetches all dashboards linked to a stream that are visible to the current user in the current space.
description: 'Fetches all dashboards linked to a stream that are visible to the current user in the current space.<br/><br/>[Required authorization] Route required privileges: read_stream.'
operationId: get-streams-name-dashboards
parameters:
- in: path
@ -52217,7 +52217,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/dashboards/_bulk:
post:
description: Bulk update dashboards linked to a stream. Can link new dashboards and delete existing ones.
description: 'Bulk update dashboards linked to a stream. Can link new dashboards and delete existing ones.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: post-streams-name-dashboards-bulk
parameters:
- description: A required header to protect against CSRF attacks
@ -52278,7 +52278,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/dashboards/{dashboardId}:
delete:
description: Unlinks a dashboard from a stream. Noop if the dashboard is not linked to the stream.
description: 'Unlinks a dashboard from a stream. Noop if the dashboard is not linked to the stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: delete-streams-name-dashboards-dashboardid
parameters:
- description: A required header to protect against CSRF attacks
@ -52316,7 +52316,7 @@ paths:
- streams
x-state: Technical Preview
put:
description: Links a dashboard to a stream. Noop if the dashboard is already linked to the stream.
description: 'Links a dashboard to a stream. Noop if the dashboard is already linked to the stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: put-streams-name-dashboards-dashboardid
parameters:
- description: A required header to protect against CSRF attacks
@ -52355,7 +52355,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/queries:
get:
description: Fetches all queries linked to a stream that are visible to the current user in the current space.
description: 'Fetches all queries linked to a stream that are visible to the current user in the current space.<br/><br/>[Required authorization] Route required privileges: read_stream.'
operationId: get-streams-name-queries
parameters:
- in: path
@ -52382,7 +52382,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/queries/_bulk:
post:
description: Bulk update queries of a stream. Can add new queries and delete existing ones.
description: 'Bulk update queries of a stream. Can add new queries and delete existing ones.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: post-streams-name-queries-bulk
parameters:
- description: A required header to protect against CSRF attacks
@ -52461,7 +52461,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/queries/{queryId}:
delete:
description: Remove a query from a stream. Noop if the query is not found on the stream.
description: 'Remove a query from a stream. Noop if the query is not found on the stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: delete-streams-name-queries-queryid
parameters:
- description: A required header to protect against CSRF attacks
@ -52499,7 +52499,7 @@ paths:
- streams
x-state: Technical Preview
put:
description: Adds a query to a stream. Noop if the query is already present on the stream.
description: 'Adds a query to a stream. Noop if the query is already present on the stream.<br/><br/>[Required authorization] Route required privileges: manage_stream.'
operationId: put-streams-name-queries-queryid
parameters:
- description: A required header to protect against CSRF attacks
@ -52548,7 +52548,7 @@ paths:
x-state: Technical Preview
/api/streams/{name}/significant_events:
get:
description: Read the significant events
description: 'Read the significant events<br/><br/>[Required authorization] Route required privileges: read_stream.'
operationId: get-streams-name-significant-events
parameters:
- in: path

View file

@ -6,3 +6,13 @@
*/
export const ASSET_VERSION = 1;
export const STREAMS_API_PRIVILEGES = {
read: 'read_stream',
manage: 'manage_stream',
} as const;
export const STREAMS_UI_PRIVILEGES = {
manage: 'manage',
show: 'show',
} as const;

View file

@ -18,7 +18,8 @@
"licensing",
"taskManager",
"alerting",
"inference"
"inference",
"features",
],
"optionalPlugins": [
"cloud",

View file

@ -11,6 +11,8 @@ import { StreamsPluginSetup, StreamsPluginStart } from './types';
export type { StreamsPluginSetup, StreamsPluginStart };
export { STREAMS_API_PRIVILEGES, STREAMS_UI_PRIVILEGES } from '../common/constants';
export const plugin: PluginInitializer<StreamsPluginSetup, StreamsPluginStart> = (
context: PluginInitializerContext
) => {

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { CoreSetup, CoreStart, PluginInitializerContext } from '@kbn/core/public';
import { ApplicationStart, CoreSetup, CoreStart, PluginInitializerContext } from '@kbn/core/public';
import { Logger } from '@kbn/logging';
import { createRepositoryClient } from '@kbn/server-route-repository-client';
@ -35,15 +35,18 @@ export class Plugin implements StreamsPluginClass {
setup(core: CoreSetup, pluginSetup: StreamsPluginSetupDependencies): StreamsPluginSetup {
this.repositoryClient = createRepositoryClient(core);
return {
status$: createStreamsStatusObservable(pluginSetup, this.repositoryClient, this.logger),
};
return {};
}
start(core: CoreStart, pluginsStart: StreamsPluginStartDependencies): StreamsPluginStart {
return {
streamsRepositoryClient: this.repositoryClient,
status$: createStreamsStatusObservable(pluginsStart, this.repositoryClient, this.logger),
status$: createStreamsStatusObservable(
pluginsStart,
core.application,
this.repositoryClient,
this.logger
),
};
}
@ -57,12 +60,19 @@ const UNKNOWN_STATUS: StreamsStatus = { status: 'unknown' };
const createStreamsStatusObservable = once(
(
deps: StreamsPluginSetupDependencies | StreamsPluginStartDependencies,
application: ApplicationStart,
repositoryClient: StreamsRepositoryClient,
logger: Logger
): Observable<StreamsStatus> => {
const isObservabilityServerless =
deps.cloud?.isServerlessEnabled && deps.cloud?.serverless.projectType === 'observability';
const hasCapabilities = application.capabilities?.streams?.show;
if (!hasCapabilities) {
return from([DISABLED_STATUS]);
}
if (isObservabilityServerless) {
return from([ENABLED_STATUS]);
}

View file

@ -14,9 +14,8 @@ export interface StreamsStatus {
status: 'unknown' | 'enabled' | 'disabled';
}
export interface StreamsPluginSetup {
status$: Observable<StreamsStatus>;
}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface StreamsPluginSetup {}
export interface StreamsPluginStart {
streamsRepositoryClient: StreamsRepositoryClient;

View file

@ -8,6 +8,7 @@
import {
CoreSetup,
CoreStart,
DEFAULT_APP_CATEGORIES,
KibanaRequest,
Logger,
Plugin,
@ -15,6 +16,8 @@ import {
PluginInitializerContext,
} from '@kbn/core/server';
import { registerRoutes } from '@kbn/server-route-repository';
import { KibanaFeatureScope } from '@kbn/features-plugin/common';
import { i18n } from '@kbn/i18n';
import { StreamsConfig, configSchema, exposeToBrowserConfig } from '../common/config';
import { streamsRouteRepository } from './routes';
import {
@ -26,6 +29,7 @@ import { AssetService } from './lib/streams/assets/asset_service';
import { RouteHandlerScopedClients } from './routes/types';
import { StreamsService } from './lib/streams/service';
import { StreamsTelemetryService } from './lib/telemetry/service';
import { STREAMS_API_PRIVILEGES, STREAMS_UI_PRIVILEGES } from '../common/constants';
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface StreamsPluginSetup {}
@ -72,6 +76,37 @@ export class StreamsPlugin
const assetService = new AssetService(core, this.logger);
const streamsService = new StreamsService(core, this.logger, this.isDev);
plugins.features.registerKibanaFeature({
id: 'streams',
name: i18n.translate('xpack.streams.featureRegistry.streamsFeatureName', {
defaultMessage: 'Streams',
}),
order: 600,
category: DEFAULT_APP_CATEGORIES.observability,
scope: [KibanaFeatureScope.Spaces, KibanaFeatureScope.Security],
app: ['streams'],
privileges: {
all: {
app: ['streams'],
savedObject: {
all: [],
read: [],
},
api: [STREAMS_API_PRIVILEGES.read, STREAMS_API_PRIVILEGES.manage],
ui: [STREAMS_UI_PRIVILEGES.show, STREAMS_UI_PRIVILEGES.manage],
},
read: {
app: ['streams'],
savedObject: {
all: [],
read: [],
},
api: [STREAMS_API_PRIVILEGES.read],
ui: [STREAMS_UI_PRIVILEGES.show],
},
},
});
registerRoutes({
repository: streamsRouteRepository,
dependencies: {

View file

@ -14,6 +14,7 @@ import {
contentPackIncludedObjectsSchema,
isIncludeAll,
} from '@kbn/content-packs-schema';
import { STREAMS_API_PRIVILEGES } from '../../../common/constants';
import { Asset } from '../../../common';
import { DashboardAsset, DashboardLink } from '../../../common/assets';
import { createServerRoute } from '../create_server_route';
@ -50,9 +51,7 @@ const exportContentRoute = createServerRoute({
}),
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
async handler({ params, request, response, getScopedClients, context }) {
@ -134,9 +133,7 @@ const importContentRoute = createServerRoute({
}),
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
async handler({ params, request, getScopedClients, context }) {
@ -210,8 +207,7 @@ const previewContentRoute = createServerRoute({
}),
security: {
authz: {
enabled: false,
reason: 'This API does not use any user credentials.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
async handler({ params }) {

View file

@ -8,6 +8,7 @@
import { z } from '@kbn/zod';
import { ErrorCause } from '@elastic/elasticsearch/lib/api/types';
import { internal } from '@hapi/boom';
import { STREAMS_API_PRIVILEGES } from '../../../common/constants';
import { Asset, DashboardAsset } from '../../../common/assets';
import { createServerRoute } from '../create_server_route';
import { ASSET_ID, ASSET_TYPE } from '../../lib/streams/assets/fields';
@ -66,9 +67,7 @@ const listDashboardsRoute = createServerRoute({
}),
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
async handler({ params, request, getScopedClients }): Promise<ListDashboardsResponse> {
@ -104,9 +103,7 @@ const linkDashboardRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
params: z.object({
@ -147,9 +144,7 @@ const unlinkDashboardRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
params: z.object({
@ -185,9 +180,7 @@ const suggestDashboardsRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
params: z.object({
@ -244,9 +237,7 @@ const bulkDashboardsRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
params: z.object({

View file

@ -6,6 +6,7 @@
*/
import { z } from '@kbn/zod';
import { STREAMS_API_PRIVILEGES } from '../../../../common/constants';
import { DashboardAsset } from '../../../../common/assets';
import { createServerRoute } from '../../create_server_route';
import { SanitizedDashboardAsset } from '../../dashboards/route';
@ -30,9 +31,7 @@ const suggestDashboardsRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
params: z.object({

View file

@ -8,6 +8,7 @@
import { UnparsedEsqlResponse, createTracedEsClient } from '@kbn/traced-es-client';
import { z } from '@kbn/zod';
import { isNumber } from 'lodash';
import { STREAMS_API_PRIVILEGES } from '../../../../common/constants';
import { createServerRoute } from '../../create_server_route';
import { excludeFrozenQuery, kqlQuery, rangeQuery } from './query_helpers';
@ -18,9 +19,7 @@ export const executeEsqlRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
params: z.object({

View file

@ -10,6 +10,7 @@ import { StreamDefinition, isGroupStreamDefinition } from '@kbn/streams-schema';
import { z } from '@kbn/zod';
import { estypes } from '@elastic/elasticsearch';
import { UnwiredIngestStreamEffectiveLifecycle } from '@kbn/streams-schema';
import { STREAMS_API_PRIVILEGES } from '../../../../../common/constants';
import { createServerRoute } from '../../../create_server_route';
import { getDataStreamLifecycle } from '../../../../lib/streams/stream_crud';
@ -27,9 +28,7 @@ export const listStreamsRoute = createServerRoute({
params: z.object({}),
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
handler: async ({ request, getScopedClients }): Promise<{ streams: ListStreamDetail[] }> => {
@ -66,9 +65,7 @@ export const streamDetailRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
params: z.object({
@ -118,9 +115,7 @@ export const resolveIndexRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
params: z.object({

View file

@ -7,6 +7,7 @@
import { isIlmLifecycle, isIngestStreamDefinition } from '@kbn/streams-schema';
import { z } from '@kbn/zod';
import { STREAMS_API_PRIVILEGES } from '../../../../../common/constants';
import { createServerRoute } from '../../../create_server_route';
import { ilmPhases } from '../../../../lib/streams/lifecycle/ilm_phases';
import { getEffectiveLifecycle } from '../../../../lib/streams/lifecycle/get_effective_lifecycle';
@ -19,9 +20,7 @@ const lifecycleStatsRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
params: z.object({
@ -62,9 +61,7 @@ const lifecycleIlmExplainRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
params: z.object({

View file

@ -13,6 +13,7 @@ import {
isUnwiredStreamDefinition,
} from '@kbn/streams-schema';
import { z } from '@kbn/zod';
import { STREAMS_API_PRIVILEGES } from '../../../../../common/constants';
import { SecurityError } from '../../../../lib/streams/errors/security_error';
import { WrongStreamTypeError } from '../../../../lib/streams/errors/wrong_stream_type_error';
import {
@ -29,9 +30,7 @@ export const sampleStreamRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
params: z.object({
@ -111,9 +110,7 @@ export const unmanagedAssetDetailsRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
params: z.object({

View file

@ -12,6 +12,7 @@ import {
processorWithIdDefinitionSchema,
} from '@kbn/streams-schema';
import { z } from '@kbn/zod';
import { STREAMS_API_PRIVILEGES } from '../../../../../common/constants';
import { SecurityError } from '../../../../lib/streams/errors/security_error';
import { checkAccess } from '../../../../lib/streams/stream_crud';
import { createServerRoute } from '../../../create_server_route';
@ -34,9 +35,7 @@ export const simulateProcessorRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
params: paramsSchema,
@ -76,9 +75,7 @@ export const processingSuggestionRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
params: suggestionsParamsSchema,

View file

@ -11,6 +11,7 @@ import {
isWiredStreamDefinition,
} from '@kbn/streams-schema';
import { z } from '@kbn/zod';
import { STREAMS_API_PRIVILEGES } from '../../../../../common/constants';
import { SecurityError } from '../../../../lib/streams/errors/security_error';
import { checkAccess } from '../../../../lib/streams/stream_crud';
import { createServerRoute } from '../../../create_server_route';
@ -24,9 +25,7 @@ export const unmappedFieldsRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
params: z.object({
@ -91,9 +90,7 @@ export const schemaFieldsSimulationRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
params: z.object({

View file

@ -13,6 +13,7 @@ import {
upsertStreamQueryRequestSchema,
} from '@kbn/streams-schema';
import { z } from '@kbn/zod';
import { STREAMS_API_PRIVILEGES } from '../../../common/constants';
import { ASSET_ID, ASSET_TYPE } from '../../lib/streams/assets/fields';
import { createServerRoute } from '../create_server_route';
export interface ListQueriesResponse {
@ -47,9 +48,7 @@ const listQueriesRoute = createServerRoute({
}),
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
async handler({ params, request, getScopedClients }): Promise<ListQueriesResponse> {
@ -80,12 +79,9 @@ const upsertQueryRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
params: z.object({
path: z.object({
name: z.string(),
@ -132,9 +128,7 @@ const deleteQueryRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
params: z.object({
@ -175,9 +169,7 @@ const bulkQueriesRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
params: z.object({

View file

@ -13,6 +13,7 @@ import {
} from '@kbn/streams-schema';
import { z } from '@kbn/zod';
import { badData } from '@hapi/boom';
import { STREAMS_API_PRIVILEGES } from '../../../../common/constants';
import { UpsertStreamResponse } from '../../../lib/streams/client';
import { createServerRoute } from '../../create_server_route';
import { readStream } from './read_stream';
@ -29,9 +30,7 @@ export const readStreamRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
params: z.object({
@ -65,9 +64,7 @@ export const listStreamsRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
params: z.object({}),
@ -92,9 +89,7 @@ export const editStreamRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
params: z.object({
@ -130,9 +125,7 @@ export const deleteStreamRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
params: z.object({

View file

@ -7,6 +7,7 @@
import { z } from '@kbn/zod';
import { conflict } from '@hapi/boom';
import { STREAMS_API_PRIVILEGES } from '../../../../common/constants';
import { NameTakenError } from '../../../lib/streams/errors/name_taken_error';
import { DisableStreamsResponse, EnableStreamsResponse } from '../../../lib/streams/client';
import { createServerRoute } from '../../create_server_route';
@ -24,9 +25,7 @@ export const enableStreamsRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
handler: async ({ request, getScopedClients }): Promise<EnableStreamsResponse> => {
@ -60,9 +59,7 @@ export const disableStreamsRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
handler: async ({ request, getScopedClients }): Promise<DisableStreamsResponse> => {

View file

@ -13,6 +13,7 @@ import {
GroupStreamUpsertRequest,
isGroupStreamDefinition,
} from '@kbn/streams-schema';
import { STREAMS_API_PRIVILEGES } from '../../../../common/constants';
import { createServerRoute } from '../../create_server_route';
import { ASSET_TYPE, ASSET_UUID } from '../../../lib/streams/assets/fields';
import { QueryAsset } from '../../../../common/assets';
@ -29,9 +30,7 @@ const readGroupRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
params: z.object({
@ -66,9 +65,7 @@ const upsertGroupRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
params: z.object({

View file

@ -14,6 +14,7 @@ import {
isWiredStreamDefinition,
} from '@kbn/streams-schema';
import { z } from '@kbn/zod';
import { STREAMS_API_PRIVILEGES } from '../../../../common/constants';
import { createServerRoute } from '../../create_server_route';
import { ASSET_ID, ASSET_TYPE } from '../../../lib/streams/assets/fields';
import { QueryAsset } from '../../../../common/assets';
@ -30,9 +31,7 @@ const readIngestRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
params: z.object({
@ -71,9 +70,7 @@ const upsertIngestRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
params: z.object({

View file

@ -7,6 +7,7 @@
import { conditionSchema } from '@kbn/streams-schema';
import { z } from '@kbn/zod';
import { STREAMS_API_PRIVILEGES } from '../../../../common/constants';
import { ResyncStreamsResponse } from '../../../lib/streams/client';
import { createServerRoute } from '../../create_server_route';
@ -22,9 +23,7 @@ export const forkStreamsRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
params: z.object({
@ -58,9 +57,7 @@ export const resyncStreamsRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.manage],
},
},
params: z.object({}),
@ -78,9 +75,7 @@ export const getStreamsStatusRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
handler: async ({ request, getScopedClients }): Promise<{ enabled: boolean }> => {

View file

@ -8,6 +8,7 @@
import { badRequest } from '@hapi/boom';
import { SignificantEventsGetResponse } from '@kbn/streams-schema';
import { z } from '@kbn/zod';
import { STREAMS_API_PRIVILEGES } from '../../../../common/constants';
import { createServerRoute } from '../../create_server_route';
import { readSignificantEvents } from './read_significant_events';
@ -28,9 +29,7 @@ export const readSignificantEventsRoute = createServerRoute({
},
security: {
authz: {
enabled: false,
reason:
'This API delegates security to the currently logged in user and their Elasticsearch permissions.',
requiredPrivileges: [STREAMS_API_PRIVILEGES.read],
},
},
handler: async ({ params, request, getScopedClients }): Promise<SignificantEventsGetResponse> => {

View file

@ -18,6 +18,7 @@ import type {
} from '@kbn/task-manager-plugin/server';
import type { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server';
import type { InferenceServerStart } from '@kbn/inference-plugin/server';
import { FeaturesPluginSetup } from '@kbn/features-plugin/server';
import type { StreamsConfig } from '../common/config';
export interface StreamsServer {
core: CoreStart;
@ -37,6 +38,7 @@ export interface StreamsPluginSetupDependencies {
encryptedSavedObjects: EncryptedSavedObjectsPluginSetup;
taskManager: TaskManagerSetupContract;
alerting: AlertingServerSetup;
features: FeaturesPluginSetup;
}
export interface StreamsPluginStartDependencies {

View file

@ -45,6 +45,8 @@
"@kbn/fleet-plugin",
"@kbn/content-packs-schema",
"@kbn/cloud-plugin",
"@kbn/es-types"
"@kbn/es-types",
"@kbn/features-plugin",
"@kbn/i18n"
]
}

View file

@ -18,6 +18,7 @@ import { i18n } from '@kbn/i18n';
import React, { useMemo, useState } from 'react';
import type { SanitizedDashboardAsset } from '@kbn/streams-plugin/server/routes/dashboards/route';
import { IngestStreamGetResponse } from '@kbn/streams-schema';
import { STREAMS_UI_PRIVILEGES } from '@kbn/streams-plugin/public';
import { AddDashboardFlyout } from './add_dashboard_flyout';
import { DashboardsTable } from './dashboard_table';
import { useDashboardsApi } from '../../hooks/use_dashboards_api';
@ -56,7 +57,14 @@ export function StreamDetailDashboardsView({
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const {
core: { featureFlags },
core: {
featureFlags,
application: {
capabilities: {
streams: { [STREAMS_UI_PRIVILEGES.manage]: canLinkAssets },
},
},
},
} = useKibana();
const renderContentPackItems = featureFlags.getBooleanValue(
@ -124,6 +132,7 @@ export function StreamDetailDashboardsView({
iconType="importAction"
iconSide="left"
color="primary"
disabled={!canLinkAssets}
onClick={() => setIsPopoverOpen(true)}
>
{i18n.translate(
@ -182,6 +191,7 @@ export function StreamDetailDashboardsView({
<EuiButton
data-test-subj="streamsAppStreamDetailAddDashboardButton"
iconType="plusInCircle"
disabled={!canLinkAssets}
onClick={() => {
setIsAddDashboardFlyoutOpen(true);
}}
@ -199,7 +209,7 @@ export function StreamDetailDashboardsView({
dashboards={filteredDashboards}
loading={dashboardsFetch.loading}
selectedDashboards={selectedDashboards}
setSelectedDashboards={setSelectedDashboards}
setSelectedDashboards={canLinkAssets ? setSelectedDashboards : undefined}
/>
{definition && isAddDashboardFlyoutOpen ? (
<AddDashboardFlyout

View file

@ -13,7 +13,9 @@ import {
isUnwiredStreamGetResponse,
} from '@kbn/streams-schema';
import { EuiFlexGroup, EuiLoadingSpinner } from '@elastic/eui';
import { STREAMS_UI_PRIVILEGES } from '@kbn/streams-plugin/public';
import { useStreamsAppFetch } from './use_streams_app_fetch';
import { useKibana } from './use_kibana';
export interface StreamDetailContextProviderProps {
name: string;
@ -33,6 +35,15 @@ export function StreamDetailContextProvider({
streamsRepositoryClient,
children,
}: React.PropsWithChildren<StreamDetailContextProviderProps>) {
const {
core: {
application: {
capabilities: {
streams: { [STREAMS_UI_PRIVILEGES.manage]: canManage },
},
},
},
} = useKibana();
const {
value: definition,
loading,
@ -50,13 +61,21 @@ export function StreamDetailContextProvider({
})
.then((response) => {
if (isWiredStreamGetResponse(response) || isUnwiredStreamGetResponse(response)) {
return response;
return {
...response,
privileges: {
...response.privileges,
// restrict the manage privilege by the Elasticsearch-level data-stream specific privilege and the Kibana-level UI privilege
// the UI should only enable manage features if the user has privileges on both levels for the current stream
manage: response.privileges.manage && canManage,
},
};
}
throw new Error('Stream detail only supports IngestStreams.');
});
},
[streamsRepositoryClient, name]
[streamsRepositoryClient, name, canManage]
);
const context = React.useMemo(

View file

@ -27,7 +27,7 @@ import {
} from '@kbn/observability-ai-assistant-plugin/public';
import type { SavedObjectTaggingPluginStart } from '@kbn/saved-objects-tagging-plugin/public';
import type { SharePublicSetup, SharePublicStart } from '@kbn/share-plugin/public/plugin';
import type { StreamsPluginSetup, StreamsPluginStart } from '@kbn/streams-plugin/public';
import type { StreamsPluginStart } from '@kbn/streams-plugin/public';
import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
/* eslint-disable @typescript-eslint/no-empty-interface*/
@ -46,7 +46,6 @@ export interface StreamsAppSetupDependencies {
discoverShared: DiscoverSharedPublicSetup;
observabilityAIAssistant: ObservabilityAIAssistantPublicSetup;
share: SharePublicSetup;
streams: StreamsPluginSetup;
unifiedSearch: {};
}

View file

@ -120,6 +120,7 @@ export default function ({ getService }: FtrProviderContext) {
'ml',
'apm',
'stackAlerts',
'streams',
'canvas',
'generalCasesV3',
'infrastructure',
@ -179,6 +180,7 @@ export default function ({ getService }: FtrProviderContext) {
'ml',
'apm',
'stackAlerts',
'streams',
'canvas',
'generalCasesV3',
'infrastructure',

View file

@ -6,7 +6,7 @@
*/
import { i18n } from '@kbn/i18n';
import { map } from 'rxjs';
import { from, map, switchMap } from 'rxjs';
import {
AppUpdater,
CoreSetup,
@ -85,8 +85,12 @@ export class ObservabilityStreamsWrapperPlugin
>,
pluginsSetup: ObservabilityStreamsWrapperSetupDependencies
): ObservabilityStreamsWrapperPublicSetup {
const startServicesPromise = coreSetup.getStartServices();
pluginsSetup.observabilityShared.navigation.registerSections(
pluginsSetup.streams.status$.pipe(
from(startServicesPromise).pipe(
switchMap(([_, pluginsStart]) =>
pluginsStart.streams.status$.pipe(
map(({ status }) => {
if (status !== 'enabled') {
return [];
@ -113,6 +117,8 @@ export class ObservabilityStreamsWrapperPlugin
];
})
)
)
)
);
coreSetup.application.register({
@ -124,7 +130,9 @@ export class ObservabilityStreamsWrapperPlugin
appRoute: '/app/streams',
category: DEFAULT_APP_CATEGORIES.observability,
order: 8001,
updater$: pluginsSetup.streams.status$.pipe(
updater$: from(startServicesPromise).pipe(
switchMap(([_, pluginsStart]) =>
pluginsStart.streams.status$.pipe(
map(({ status }): AppUpdater => {
return (app) => {
if (status !== 'enabled') {
@ -138,6 +146,8 @@ export class ObservabilityStreamsWrapperPlugin
};
};
})
)
)
),
mount: async (appMountParameters: AppMountParameters<unknown>) => {
// Load application bundle and Get start services

View file

@ -13,7 +13,7 @@ import type {
ObservabilitySharedPluginSetup,
ObservabilitySharedPluginStart,
} from '@kbn/observability-shared-plugin/public';
import type { StreamsPluginSetup, StreamsPluginStart } from '@kbn/streams-plugin/public';
import type { StreamsPluginStart } from '@kbn/streams-plugin/public';
import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
import type { SharePublicSetup, SharePublicStart } from '@kbn/share-plugin/public/plugin';
import type { SavedObjectTaggingPluginStart } from '@kbn/saved-objects-tagging-plugin/public';
@ -29,7 +29,6 @@ import { StreamsAppPublicSetup, StreamsAppPublicStart } from '@kbn/streams-app-p
export interface ConfigSchema {}
export interface ObservabilityStreamsWrapperSetupDependencies {
streams: StreamsPluginSetup;
streamsApp: StreamsAppPublicSetup;
dataViews: DataViewsPublicPluginSetup;
observabilityShared: ObservabilitySharedPluginSetup;

View file

@ -280,6 +280,7 @@ export default function ({ getService }: FtrProviderContext) {
'readFlappingSettings',
],
maintenanceWindow: ['all', 'read', 'minimal_all', 'minimal_read'],
streams: ['all', 'read', 'minimal_all', 'minimal_read'],
guidedOnboardingFeature: ['all', 'read', 'minimal_all', 'minimal_read'],
aiAssistantManagementSelection: ['all', 'read', 'minimal_all', 'minimal_read'],
inventory: ['all', 'read', 'minimal_all', 'minimal_read'],

View file

@ -75,6 +75,7 @@ export default function ({ getService }: FtrProviderContext) {
filesSharedImage: ['all', 'read', 'minimal_all', 'minimal_read'],
rulesSettings: ['all', 'read', 'minimal_all', 'minimal_read'],
maintenanceWindow: ['all', 'read', 'minimal_all', 'minimal_read'],
streams: ['all', 'read', 'minimal_all', 'minimal_read'],
guidedOnboardingFeature: ['all', 'read', 'minimal_all', 'minimal_read'],
aiAssistantManagementSelection: ['all', 'read', 'minimal_all', 'minimal_read'],
inventory: ['all', 'read', 'minimal_all', 'minimal_read'],
@ -380,6 +381,7 @@ export default function ({ getService }: FtrProviderContext) {
'readFlappingSettings',
],
maintenanceWindow: ['all', 'read', 'minimal_all', 'minimal_read'],
streams: ['all', 'read', 'minimal_all', 'minimal_read'],
guidedOnboardingFeature: ['all', 'read', 'minimal_all', 'minimal_read'],
aiAssistantManagementSelection: ['all', 'read', 'minimal_all', 'minimal_read'],
inventory: ['all', 'read', 'minimal_all', 'minimal_read'],

View file

@ -102,6 +102,7 @@ export function createTestSuiteFactory({ getService }: DeploymentAgnosticFtrProv
'siem',
'siemV2',
'slo',
'streams',
'uptime',
],
solution: 'es',

View file

@ -106,6 +106,7 @@ export function getTestSuiteFactory(context: DeploymentAgnosticFtrProviderContex
'siem',
'siemV2',
'slo',
'streams',
'uptime',
],
}),

View file

@ -94,6 +94,7 @@ const ALL_SPACE_RESULTS: Space[] = [
'siem',
'siemV2',
'slo',
'streams',
'uptime',
],
solution: 'es',

View file

@ -65,6 +65,7 @@ export default function ({ getService }: FtrProviderContext) {
rulesSettings: 0,
maintenanceWindow: 0,
stackAlerts: 0,
streams: 0,
generalCases: 0,
generalCasesV2: 0,
generalCasesV3: 0,