diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index 16d9cac6e5..cf3cbff8a7 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -474,6 +474,30 @@ jobs: - name: Build docs run: make docs-install docs-build + docs-fmt-check: + name: Docs Format Check + runs-on: ubuntu-24.04 + needs: check-changes + if: ${{ needs.check-changes.outputs.docs == 'true' }} + steps: + - name: Check out code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Check docs formatting + run: make docs-install docs-fmt-check + + docs-lint-check: + name: Docs Lint Check + runs-on: ubuntu-24.04 + needs: check-changes + if: ${{ needs.check-changes.outputs.docs == 'true' }} + steps: + - name: Check out code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Lint docs + run: make docs-install docs-lint-check + # This job is required to complete before merging, and is set as a branch # protection rule: # https://github.com/open-policy-agent/opa/settings/branch_protection_rules @@ -495,6 +519,8 @@ jobs: go-version-build, rego-check-pr, docs-build, + docs-fmt-check, + docs-lint-check, ] if: always() steps: diff --git a/docs/Makefile b/docs/Makefile index 9545b55ed0..9c56f62227 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -32,3 +32,19 @@ generate-cli-docs: .PHONY: smoke-test smoke-test: ./bin/smoke-test.sh + +.PHONY: fmt +fmt: + npx dprint fmt + +.PHONY: fmt-check +fmt-check: + npx dprint check + +.PHONY: lint +lint: + npx eslint --fix . + +.PHONY: lint-check +lint-check: + npx eslint . diff --git a/docs/devel/DEVELOPMENT.md b/docs/devel/DEVELOPMENT.md index 47c67d4580..f86bf07e23 100644 --- a/docs/devel/DEVELOPMENT.md +++ b/docs/devel/DEVELOPMENT.md @@ -1,4 +1,4 @@ ## Development The development guide has become part of the Contributing documentation -and can be found [here](https://www.openpolicyagent.org/docs/contrib-development). \ No newline at end of file +and can be found [here](https://www.openpolicyagent.org/docs/contrib-development). diff --git a/docs/devel/RELEASE.md b/docs/devel/RELEASE.md index 0665a1e4e2..cd37a4da1b 100644 --- a/docs/devel/RELEASE.md +++ b/docs/devel/RELEASE.md @@ -12,7 +12,7 @@ Versioning involves maintaining the following files: The steps below explain how to update these files. In addition, the repository should be tagged with the semantic version identifying the release. -Publishing involves creating a new *Release* on GitHub with the relevant +Publishing involves creating a new _Release_ on GitHub with the relevant CHANGELOG.md snippet and uploading the binaries from the build phase. > Note: This release process is subject to change without notice. @@ -42,87 +42,87 @@ standard GitHub fork workflow. See [OPA Dev Instructions](DEVELOPMENT.md) 1. The following steps assume a remote named `upstream` exists that references the OPA source repository. As needed, add an `upstream` remote for the repository: - ``` - git remote add upstream git@github.com:open-policy-agent/opa.git - git fetch --tags upstream - ``` + ``` + git remote add upstream git@github.com:open-policy-agent/opa.git + git fetch --tags upstream + ``` - Note: This stage can fail if you have not registered an [SSH key](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account) - on your Github account. + Note: This stage can fail if you have not registered an [SSH key](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account) + on your Github account. 1. Create a release branch off of `main`, to ensure you don't mangle your fork while creating the release: - ``` - git checkout -b release-v origin/main - ``` + ``` + git checkout -b release-v origin/main + ``` 1. Create a [personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) for GitHub with the 'read:org' scope. Export it to the `GITHUB_TOKEN` environment variable. 1. Execute the release-patch target to generate boilerplate patch. Give the semantic version of the release: - ``` - make release-patch VERSION=0.12.8 > ~/release.patch - ``` + ``` + make release-patch VERSION=0.12.8 > ~/release.patch + ``` 1. Apply the release patch to the working copy and preview the changes: - ``` - patch -p1 < ~/release.patch - git diff - ``` + ``` + patch -p1 < ~/release.patch + git diff + ``` - > Amend the changes as necessary, e.g., many of the Fixes and Miscellaneous - > changes may not be user facing (so remove them). Also, if there have been - > any significant API changes, call them out in their own sections. + > Amend the changes as necessary, e.g., many of the Fixes and Miscellaneous + > changes may not be user facing (so remove them). Also, if there have been + > any significant API changes, call them out in their own sections. 1. Commit the changes and push to remote repository fork. - ``` - git add . - git commit -s -m "Prepare v release" - git push origin release-v - ``` + ``` + git add . + git commit -s -m "Prepare v release" + git push origin release-v + ``` 1. Create a Pull Request for the release preparation commit. 1. Once the Pull Request has merged fetch the latest changes and tag the commit to prepare for publishing: - ``` - git fetch upstream - git tag v upstream/main - ``` + ``` + git fetch upstream + git tag v upstream/main + ``` - > Note: Ensure that tag is pointing to the correct commit ID! It must be the merged release preparation commit. + > Note: Ensure that tag is pointing to the correct commit ID! It must be the merged release preparation commit. 1. Create a new branch for the dev-patch work: - ``` - git checkout -b dev-v origin/main - ``` + ``` + git checkout -b dev-v origin/main + ``` 1. Execute the dev-patch target to generate boilerplate patch. Give the semantic version of the next release: - ``` - make dev-patch VERSION=0.12.9 > ~/dev.patch - ``` + ``` + make dev-patch VERSION=0.12.9 > ~/dev.patch + ``` - > The semantic version of the next release typically increments the point version by one. + > The semantic version of the next release typically increments the point version by one. 1. Apply the patch to the working copy and preview the changes: - ``` - patch -p1 < ~/dev.patch - git diff - ``` + ``` + patch -p1 < ~/dev.patch + git diff + ``` 1. Commit the changes and push to remote repository fork. - ``` - git commit -a -s -m "Prepare v development" - git push origin dev-v - ``` + ``` + git commit -a -s -m "Prepare v development" + git push origin dev-v + ``` 1. Create a Pull Request for the development preparation commit. @@ -130,9 +130,9 @@ standard GitHub fork workflow. See [OPA Dev Instructions](DEVELOPMENT.md) 1. Push the release tag to remote source repository. - ``` - git push upstream v - ``` + ``` + git push upstream v + ``` > Note: Only OPA maintainers will have permissions to perform this step. @@ -150,14 +150,14 @@ standard GitHub fork workflow. See [OPA Dev Instructions](DEVELOPMENT.md) involved here. - The docs and website should update and be published automatically. If they are not you can trigger one by a couple of methods: - - Login to Netlify (requires permission for the project) and manually trigger a build. - - Post to the build webhook via: - ```bash - curl -X POST -d {} https://api.netlify.com/build_hooks/612e8941ffe30d2902bcce80 - ``` + - Login to Netlify (requires permission for the project) and manually trigger a build. + - Post to the build webhook via: + ```bash + curl -X POST -d {} https://api.netlify.com/build_hooks/612e8941ffe30d2902bcce80 + ``` - The Algolia search index is automatically updated when the site is crawled daily at 20:30 (UTC). The crawling process takes around 25 minutes to complete and can be triggered from - [crawler.algolia.com](https://crawler.algolia.com) (login details required). + [crawler.algolia.com](https://crawler.algolia.com) (login details required). # Bugfix Release Process @@ -219,7 +219,7 @@ Open a Pull Request against the upstream release branch. Be careful to open the Pull Request against the correct upstream release branch. **DO NOT** open/merge the Pull Request into main or other release branches. -> Note: Make sure to do a "Rebase and merge" and NOT a squash when merging the PR, to preserve the cherry-picked commits. +> Note: Make sure to do a "Rebase and merge" and NOT a squash when merging the PR, to preserve the cherry-picked commits. > Alternatively, the cherry-picks can be pushed to `upstream` before submitting the PR. Once the Pull Request has merged fetch the latest changes and tag the commit to diff --git a/docs/docs/cicd.md b/docs/docs/cicd.md index 093705cf63..2a799c034d 100644 --- a/docs/docs/cicd.md +++ b/docs/docs/cicd.md @@ -87,6 +87,7 @@ jobs: ``` Here's some examples of how we use these actions in our own CI/CD pipelines for OPA! + - [Pull Request Workflow File](https://github.com/open-policy-agent/opa/blob/main/.github/workflows/pull-request.yaml) - [PR Where Action was Introduced](https://github.com/open-policy-agent/opa/pull/8183/files#diff-a8619735ff14304aa0514284f86ff5145b0a6bae2e76a37faeb0ad899a3d8db4R27-R30) diff --git a/docs/docs/configuration.md b/docs/docs/configuration.md index 9862491b99..86946f20f6 100644 --- a/docs/docs/configuration.md +++ b/docs/docs/configuration.md @@ -187,28 +187,28 @@ OPA will authenticate using a bearer token obtained through the OAuth2 [client c Rather than providing a client secret along with the request for an access token, the client [asserts](https://tools.ietf.org/html/rfc7521#section-4.2) its identity in the form of a signed JWT. Following successful authentication at the token endpoint the returned token will be cached for subsequent requests for the duration of its lifetime. Note that as per the [OAuth2 standard](https://tools.ietf.org/html/rfc6749#section-2.3.1), only the HTTPS scheme is supported for the token endpoint URL. -| Field | Type | Required | Description | -| --------------------------------------------------------------------- | ---------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `services[_].credentials.oauth2.token_url` | `string` | Yes | URL pointing to the token endpoint at the OAuth2 authorization server. | -| `services[_].credentials.oauth2.grant_type` | `string` | No | Defaults to `client_credentials`. | -| `services[_].credentials.oauth2.client_id` | `string` | No | The client ID to use for authentication. | -| `services[_].credentials.oauth2.signing_key` | `string` | No | Reference to private key used for signing the JWT. Required if `aws_kms` is not provided | -| `services[_].credentials.oauth2.thumbprint` | `string` | No | Certificate thumbprint to use for x5t header generation. | -| `services[_].credentials.oauth2.additional_claims` | `map` | No | Map of claims to include in the JWT (see notes below) | -| `services[_].credentials.oauth2.include_jti_claim` | `bool` | No | Include a uniquely generated `jti` claim in any issued JWT | -| `services[_].credentials.oauth2.scopes` | `[]string` | No | Optional list of scopes to request for the token. | -| `services[_].credentials.oauth2.aws_kms.name` | `string` | No | To specify a KMS key, use its key ID, key ARN, alias name, or alias ARN. Required only for signing with AWS KMS. | -| `services[_].credentials.oauth2.aws_kms.algorithm` | `string` | No | Specifies the signing algorithm used by the key `aws_kms.name` `(ECDSA_SHA_256, ECDSA_SHA_384 or ECDSA_SHA_512)`. Required only for signing with AWS KMS. | -| `services[_].credentials.oauth2.aws_signing` | `{}` | No | AWS credentials for signing requests. Required if `aws_kms` is provided. | -| `services[_].credentials.oauth2.azure_keyvault.key` | `string` | No | Specify what key name should be used for signing. | -| `services[_].credentials.oauth2.azure_keyvault.key_version` | `string` | No | Key version that should be used for signing. Will used latest if not specified | -| `services[_].credentials.oauth2.azure_keyvault.key_algorithm` | `string` | No | Specifies the signing algorithm used by the key `azure_keyvault.key`. `ES256, ES256K, PS256, RS256, ES384, PS384, RS384, ES512, PS512 or RS512)` | -| `services[_].credentials.oauth2.azure_keyvault.vault` | `string` | No | The name of the azure keyvault. used for interpolation of URL. | -| `services[_].credentials.oauth2.azure_keyvault.api_version` | `string` | No | The version of the [azure keyvault sign api](https://learn.microsoft.com/en-us/rest/api/keyvault/keys/sign/sign?view=rest-keyvault-keys-2025-07-01). Defaults to "7.4" | -| `services[_].credentials.oauth2.azure_signing.service` | `string` | No | What azure service to use for signing. only valid service currently is "keyvault". | -| `services[_].credentials.oauth2.azure_signing.azure_managed_identity` | `{}` | No | What managed identity OPA will try to use for auth in azure. Identity has to have signing rights to the key in `azure_keyvault.key`. see [managed-identity](#azure-managed-identities-token) for more info. | -| `services[_].credentials.oauth2.client_assertion_path` | `string` | No | To specify a path to find a client assertion file. Used for Azure Workload Identity. | -| `services[_].credentials.oauth2.client_assertion` | `string` | No | To specify a client assertion. Used for Azure Workload Identity. | +| Field | Type | Required | Description | +| --------------------------------------------------------------------- | ---------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `services[_].credentials.oauth2.token_url` | `string` | Yes | URL pointing to the token endpoint at the OAuth2 authorization server. | +| `services[_].credentials.oauth2.grant_type` | `string` | No | Defaults to `client_credentials`. | +| `services[_].credentials.oauth2.client_id` | `string` | No | The client ID to use for authentication. | +| `services[_].credentials.oauth2.signing_key` | `string` | No | Reference to private key used for signing the JWT. Required if `aws_kms` is not provided | +| `services[_].credentials.oauth2.thumbprint` | `string` | No | Certificate thumbprint to use for x5t header generation. | +| `services[_].credentials.oauth2.additional_claims` | `map` | No | Map of claims to include in the JWT (see notes below) | +| `services[_].credentials.oauth2.include_jti_claim` | `bool` | No | Include a uniquely generated `jti` claim in any issued JWT | +| `services[_].credentials.oauth2.scopes` | `[]string` | No | Optional list of scopes to request for the token. | +| `services[_].credentials.oauth2.aws_kms.name` | `string` | No | To specify a KMS key, use its key ID, key ARN, alias name, or alias ARN. Required only for signing with AWS KMS. | +| `services[_].credentials.oauth2.aws_kms.algorithm` | `string` | No | Specifies the signing algorithm used by the key `aws_kms.name` `(ECDSA_SHA_256, ECDSA_SHA_384 or ECDSA_SHA_512)`. Required only for signing with AWS KMS. | +| `services[_].credentials.oauth2.aws_signing` | `{}` | No | AWS credentials for signing requests. Required if `aws_kms` is provided. | +| `services[_].credentials.oauth2.azure_keyvault.key` | `string` | No | Specify what key name should be used for signing. | +| `services[_].credentials.oauth2.azure_keyvault.key_version` | `string` | No | Key version that should be used for signing. Will used latest if not specified | +| `services[_].credentials.oauth2.azure_keyvault.key_algorithm` | `string` | No | Specifies the signing algorithm used by the key `azure_keyvault.key`. `ES256, ES256K, PS256, RS256, ES384, PS384, RS384, ES512, PS512 or RS512)` | +| `services[_].credentials.oauth2.azure_keyvault.vault` | `string` | No | The name of the azure keyvault. used for interpolation of URL. | +| `services[_].credentials.oauth2.azure_keyvault.api_version` | `string` | No | The version of the [azure keyvault sign api](https://learn.microsoft.com/en-us/rest/api/keyvault/keys/sign/sign?view=rest-keyvault-keys-2025-07-01). Defaults to "7.4" | +| `services[_].credentials.oauth2.azure_signing.service` | `string` | No | What azure service to use for signing. only valid service currently is "keyvault". | +| `services[_].credentials.oauth2.azure_signing.azure_managed_identity` | `{}` | No | What managed identity OPA will try to use for auth in azure. Identity has to have signing rights to the key in `azure_keyvault.key`. see [managed-identity](#azure-managed-identities-token) for more info. | +| `services[_].credentials.oauth2.client_assertion_path` | `string` | No | To specify a path to find a client assertion file. Used for Azure Workload Identity. | +| `services[_].credentials.oauth2.client_assertion` | `string` | No | To specify a client assertion. Used for Azure Workload Identity. | Two claims will always be included in the issued JWT: `iat` and `exp`. Any other claims will be populated from the `additional_claims` map. @@ -285,7 +285,8 @@ bundles: ``` The following is an example of using the client credentials grant type with JWT -client authentication & Azure Keyvault signing of client assertions. +client authentication & Azure Keyvault signing of client assertions. + ```yaml services: remote: @@ -407,8 +408,8 @@ The AWS service for which to sign the request can be specified in the `service` The AWS signature version to sign the request with can be specified in the `signature_version` field. If omitted, the default is `4`. The only other valid value is `4a`. -| Field | Type | Required | Description | -| ------------------------------------------------------ | -------- | -------- | ------------------------------------------------------------------------------ | +| Field | Type | Required | Description | +| ------------------------------------------------------ | -------- | -------- | -------------------------------------------------------------------------------- | | `services[_].credentials.s3_signing.service` | `string` | No | The AWS service to sign requests with, e.g. `execute-api` or `s3`. Default: `s3` | | `services[_].credentials.s3_signing.signature_version` | `string` | No | The AWS signature version to sign requests with, e.g. `4` or `4a`. Default: `4` | @@ -439,15 +440,14 @@ request OPA will re-read the credentials from the file and use them for authenti #### Using SSO Profile Credentials -If specifying `sso_credentials`, OPA will expect to find an sso profile configured as explained in [SSO Profiles](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html) and stored in the [config](https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html) file on disk. +If specifying `sso_credentials`, OPA will expect to find an sso profile configured as explained in [SSO Profiles](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html) and stored in the [config](https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html) file on disk. On each request, Opa will try to use cached token acquired credentials using the SSO credentials. In case the current token has expired, OPA will try to refresh the token using the SSO refresh token, assuming the SSO session is still valid. New token will be cached in memory. - -| Field | Type | Required | Description | -| --- | --- | --- | --- | -| `services[_].credentials.s3_signing.sso_credentials.path` | `string` | No | The path to the shared config file. If empty, OPA will look for the `AWS_CONFIG_FILE` env variable. If the variable is not set, the path defaults to the current user's home directory. `~/.aws/config` (Linux & Mac) or `%USERPROFILE%\.aws\config` (Windows) | -| `services[_].credentials.s3_signing.sso_credentials.profile` | `string` | No | AWS Profile to extract sso session from the config file. If empty, OPA will look for the `AWS_PROFILE` env variable. If the variable is not set, the `default` profile will be used | -| `services[_].credentials.s3_signing.sso_credentials.aws_region` | `string` | No | The AWS region to use for the AWS signing service credential method. If unset, the `AWS_REGION` environment variable must be set | +| Field | Type | Required | Description | +| --------------------------------------------------------------- | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `services[_].credentials.s3_signing.sso_credentials.path` | `string` | No | The path to the shared config file. If empty, OPA will look for the `AWS_CONFIG_FILE` env variable. If the variable is not set, the path defaults to the current user's home directory. `~/.aws/config` (Linux & Mac) or `%USERPROFILE%\.aws\config` (Windows) | +| `services[_].credentials.s3_signing.sso_credentials.profile` | `string` | No | AWS Profile to extract sso session from the config file. If empty, OPA will look for the `AWS_PROFILE` env variable. If the variable is not set, the `default` profile will be used | +| `services[_].credentials.s3_signing.sso_credentials.aws_region` | `string` | No | The AWS region to use for the AWS signing service credential method. If unset, the `AWS_REGION` environment variable must be set | #### Using EC2 Metadata Credentials @@ -829,7 +829,7 @@ included in the actual bundle gzipped tarball. ## Decision Logs | Field | Type | Required | Description | -|----------------------------------------------------|-----------|----------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| -------------------------------------------------- | --------- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `decision_logs.service` | `string` | No | Name of the service to use to contact remote server. If no `plugin` is specified, and `console` logging is disabled, this will default to the first `service` name defined in the Services configuration. | | `decision_logs.partition_name` | `string` | No | Deprecated: Use `resource` instead. Path segment to include in status updates. | | `decision_logs.resource` | `string` | No (default: `/logs`) | Full path to use for sending decision logs to a remote server. | @@ -917,12 +917,12 @@ this cache is utilized by the `regex` and `glob` built-in functions for compiled respectively, the `json.schema_match` built-in function for compiled JSON schemas, and any `graphql` built-in function that requires GraphQL schemas. -| Field | Type | Required | Description | -| ------------------------------------------------------------------------ | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `caching.inter_query_builtin_cache.max_size_bytes` | `int64` | No | Inter-query cache size limit in bytes. OPA will drop old items from the cache if this limit is exceeded. By default, no limit is set. | -| `caching.inter_query_builtin_cache.forced_eviction_threshold_percentage` | `int64` | No | Threshold limit configured as percentage of `caching.inter_query_builtin_cache.max_size_bytes`, when exceeded OPA will start dropping old items prematurely. By default, set to `100`. | -| `caching.inter_query_builtin_cache.stale_entry_eviction_period_seconds` | `int64` | No | Stale entry eviction period in seconds. OPA will drop expired items from the cache every `stale_entry_eviction_period_seconds`. By default, set to `0` indicating stale entry eviction is disabled. | -| `caching.inter_query_builtin_value_cache.max_num_entries` | `int` | No | Maximum number of entries in the Inter-query value cache. OPA will drop random items from the cache if this limit is exceeded. By default, set to `0` indicating unlimited size. | +| Field | Type | Required | Description | +| ------------------------------------------------------------------------ | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `caching.inter_query_builtin_cache.max_size_bytes` | `int64` | No | Inter-query cache size limit in bytes. OPA will drop old items from the cache if this limit is exceeded. By default, no limit is set. | +| `caching.inter_query_builtin_cache.forced_eviction_threshold_percentage` | `int64` | No | Threshold limit configured as percentage of `caching.inter_query_builtin_cache.max_size_bytes`, when exceeded OPA will start dropping old items prematurely. By default, set to `100`. | +| `caching.inter_query_builtin_cache.stale_entry_eviction_period_seconds` | `int64` | No | Stale entry eviction period in seconds. OPA will drop expired items from the cache every `stale_entry_eviction_period_seconds`. By default, set to `0` indicating stale entry eviction is disabled. | +| `caching.inter_query_builtin_value_cache.max_num_entries` | `int` | No | Maximum number of entries in the Inter-query value cache. OPA will drop random items from the cache if this limit is exceeded. By default, set to `0` indicating unlimited size. | | `caching.inter_query_builtin_value_cache.named.io_jwt.max_num_entries` | `int` | No | Maximum number of entries in the `io_jwt` cache, used by the [`io.jwt` token verification](./policy-reference/builtins/tokens) built-in functions. OPA will drop random items from the cache if this limit is exceeded. By default, this cache is disabled. | | `caching.inter_query_builtin_value_cache.named.graphql.max_num_entries` | `int` | No | Maximum number of entries in the `graphql` cache, used by the [`graphql` builtins](./policy-reference/builtins/graphql) built-in functions to cache parsed schemas. OPA will drop random items from the cache if this limit is exceeded. By default, this cache is set to a maximum of 10 entries. | diff --git a/docs/docs/filtering/column-masks.md b/docs/docs/filtering/column-masks.md index b6f415d426..d785ff1510 100644 --- a/docs/docs/filtering/column-masks.md +++ b/docs/docs/filtering/column-masks.md @@ -10,13 +10,11 @@ Column masking rules in Rego are used to generate an object that specifies exact You will develop an intuition for what valid masking rules look like, and how to build default-deny and default-allow masking policies. ::: - ### What is Column Masking? For our data filtering use case, a row might be returned from the database that has a sensitive column present. We still want the application to be able to display everything it can to the user, but ideally hiding or modifying the sensitive values before display. - ## Format of a Column Masks Object The column masks are structured as a nested object, with the structure: @@ -66,7 +64,6 @@ In the above example, `users.id` and `tickets.description` will be replaced with Note that the value keyed under `users.id` is **empty**, which implies "show value". This can be useful in default-deny masking policies to allow a column through under certain conditions. ::: - ## Creating a default-deny style masking policy For our running example, we will be adding column masking to a support ticket application, where the fields of a tickets that a user can see is determined by their role. @@ -117,6 +114,7 @@ masks.tickets.description.replace.value := {} if { "admin" in data.roles[input.tenant][input.user] } ``` + @@ -127,10 +125,10 @@ masks.tickets.description.replace.value := {} if { "ceasar": ["resolver"] } ``` + - ### Reader role A Reader should be able to only see the masked value for the `tickets.description` field, because they are not an Admin, and so they get the default rule's result. @@ -168,7 +166,6 @@ Content-Type: application/json } ``` - ### Admin Role An Admin should be able to see every field of every ticket, since their role triggers a dedicated rule body that removes the masking function. @@ -202,7 +199,6 @@ Content-Type: application/json } ``` - ## Creating a default-allow style masking policy For this example, we will keep the support ticket application setup from before. We are still limiting which fields of a tickets that a user can see, based on their role. @@ -230,6 +226,7 @@ masks.tickets.description.replace.value := "" if { "reader" in data.roles[input.tenant][input.user] } ``` + @@ -240,10 +237,10 @@ masks.tickets.description.replace.value := "" if { "ceasar": ["resolver"] } ``` + - ### Reader role A Reader should see the masked value for the `tickets.description` field. @@ -281,7 +278,6 @@ Content-Type: application/json } ``` - ### Resolver Role A Resolver should be able to see every field of every ticket, since they're not one of the targeted roles. diff --git a/docs/docs/filtering/fragment.md b/docs/docs/filtering/fragment.md index d92f15ff81..4fd9c79776 100644 --- a/docs/docs/filtering/fragment.md +++ b/docs/docs/filtering/fragment.md @@ -17,7 +17,6 @@ Not every construct is supported for every target. For a step-by-step walkthrough of evaluating a Rego policy _partially_, see [Evaluating a data filter policy](./partial-evaluation). ::: - ### What is Partial Evaluation? The translation of data policies into queries (like SQL WHERE clauses) is driven by _partial evaluation (PE)_ of a Rego query. @@ -30,7 +29,6 @@ The _unknown_ values that remain during partial evaluation represent the pieces When only _known_ values are used, **you can use all of Rego.** ::: - ## Example Preamble In our running example, we'll assume a table `fruits` with columns `name`, `colour`, and `price`. These **unknown values** are represented with `input..` e.g. `input.fruits.name` @@ -55,13 +53,13 @@ Our data filters also depend on user information. These **known values** are rep } ``` - ## Simple comparisons The fragment supports simple comparisons, such as `==`, `!=`, `<`, `>`, `<=`, `>=`, between _unknown_ and _known_ values. It is not important if the _unknown_ is on the left-hand side ("LHS") or right-hand side ("RHS"), but it is critical that only one side is _unknown_: :::tip OK + ```rego package filters @@ -78,6 +76,7 @@ As you can see the _known_ values from `input.user` have been replaced. ::: :::danger NOT OK + ```rego package filters @@ -86,6 +85,7 @@ include if { input.fruits.price # plain unknown } ``` + ::: :::info SQL @@ -96,19 +96,23 @@ package filters include if input.fruits.name != input.fruits.colour ``` + SQL target: `WHERE name <> colour` ::: :::info "Is Anything" For SQL and UCAST/Prisma, it's valid to assert that a field exists by unifying it with a wildcard: + ```rego package filters include if input.fruits.price = _ ``` + SQL target: `WHERE name IS NOT NULL` A more common way to do this would be function definition shorthands, like + ```rego package filters @@ -124,7 +128,6 @@ matches(x, x) # exact match Here, the first `matches` definition would yield an expression like `_ = input.fruit.name` in the partial evaluation results. ::: - ## Built-in Functions Certain built-in functions can be translated with certain restrictions: @@ -137,6 +140,7 @@ Certain built-in functions can be translated with certain restrictions: These built-in functions can only be used with _unknowns_ on the left-hand side. :::tip OK + ```rego package filters @@ -150,6 +154,7 @@ SQL target: `WHERE name LIKE 'ba%' AND colour IN ('blue', 'green')`. ::: :::danger NOT OK + ```rego package filters @@ -159,12 +164,12 @@ include if { regexp.match(input.fruits.name, '^b[an]+$') # unsupported builtin (for unknown values) } ``` + ::: Other built-in functions are not supported **for usage with _unknown_ values**. If your filtering rules use other built-ins with _known values_, that's OK -- see below for an example. - ## Rules and functions Many Rego constructs are available for building filters, with certain restrictions: @@ -175,6 +180,7 @@ Many Rego constructs are available for building filters, with certain restrictio Nonetheless, you can use rules and functions to structure your policy, as long as these restrictions are observed: :::tip OK + ```rego package filters @@ -198,6 +204,7 @@ SQL target: `WHERE name = 'pineapple'` if the user's email is not ending in `@co ::: :::danger NOT OK + ```rego package filters @@ -206,14 +213,15 @@ include if only_pineapples default only_pineapples := false # default rule only_pineapples if input.fruits.name == "pineapple" ``` -::: +::: ## `not` expressions Expressions using `not` are permitted for [simple expressions](#simple-comparisons) and [built-in functions](#built-in-functions). `not` combined with a _unknown_ value or a rule reference is not allowed. :::tip OK + ```rego package filters @@ -227,6 +235,7 @@ SQL target: `WHERE (NOT name = 'apple' AND NOT colour IN ('blue', 'green'))`. ::: :::danger NOT OK + ```rego package filters @@ -236,4 +245,5 @@ include if not apple_ish # not + rule apple_ish if endswith(input.fruits.name, "apple") apple_ish if startswith(input.fruits.name, "apple") ``` + ::: diff --git a/docs/docs/filtering/index.md b/docs/docs/filtering/index.md index 066c855274..edad39bc02 100644 --- a/docs/docs/filtering/index.md +++ b/docs/docs/filtering/index.md @@ -8,7 +8,6 @@ Data Filtering is a common use case for authorization that goes beyond "allow or It is often related to searching (or listing) multiple entities. Here, we start with a problem exposition before going into the details of data filtering with OPA in the next sections. - ## Evaluation vs Search **Authorization evaluation** questions ask "Can `subject` do `action` to `resource` (with `context`)?", e.g. diff --git a/docs/docs/filtering/partial-evaluation.md b/docs/docs/filtering/partial-evaluation.md index dd5c53a818..9ffa0d66d1 100644 --- a/docs/docs/filtering/partial-evaluation.md +++ b/docs/docs/filtering/partial-evaluation.md @@ -64,6 +64,7 @@ include if { include if input.products.price == "free" ``` + The first `include` rule is evaluated. @@ -93,6 +94,7 @@ include if { include if input.products.price == "free" ``` + The expression `input.users.name == user` uses `user`, which is _known_, "dana". @@ -128,6 +130,7 @@ include if { include if input.products.price == "free" ``` + Our expression's LHS is known, "low", which is not different from "low". @@ -161,6 +164,7 @@ include if { include if input.products.price == "free" ``` + Evaluating our second rule body, we again get a condition from the comparison with `user`, which is `input.user`, and known to be "dana": @@ -168,6 +172,7 @@ Evaluating our second rule body, we again get a condition from the comparison wi ```rego input.users.name == "dana" ``` + @@ -193,6 +198,7 @@ include if { include if input.products.price == "free" ``` + The expression `input.budget == "low"` has only known parts, `input.budget`, and "low", and is indeed true. @@ -222,6 +228,7 @@ include if { include if input.products.price == "free" ``` + The next expression, `input.products.price < 500`, involves a number literal and an unknown, and thus adds a condition: @@ -257,11 +264,13 @@ include if { # highlight-next-line include if input.products.price == "free" ``` + As with every new rule body, the set of conditions is _reset_. This expression includes one unknown and one literal, so it adds a condition to our set: + ```rego input.products.price == "free" ``` @@ -284,9 +293,11 @@ It has yielded two sets of conditions, **A** and **B**, which form the basis of input.users.name == "dana" input.products.price < 500 ``` + ```rego title="B (Rego)" input.products.price == "free" ``` + @@ -302,20 +313,22 @@ When translating, each of the sets is translated into SQL expressions: ```sql title="A (SQL)" users.name = "dana" AND products.price < 500 ``` + ```sql title="B (SQL)" products.price = "free" ``` + --- Finally, the two are combined with `OR`: + ```sql title="A OR B" (users.name = "dana" AND products.price < 500) OR products.price = "free" ``` - ## Next Steps - To learn more about which Rego expressions can be used in filter policies, continue to [Writing valid data filtering policies](./fragment). diff --git a/docs/docs/filtering/ucast-syntax.md b/docs/docs/filtering/ucast-syntax.md index c151bf7fea..5ad7b23cfc 100644 --- a/docs/docs/filtering/ucast-syntax.md +++ b/docs/docs/filtering/ucast-syntax.md @@ -4,20 +4,19 @@ description: UCAST Syntax sidebar_position: 5 --- - # UCAST Syntax The data filtering support makes use of the [Universal Conditions AST (UCAST)](https://github.com/stalniy/ucast) project to represent (as JSON) a universal set of conditions that can be applied to filter data. UCAST allows 3 types of nodes in the tree: + - **Document-level Condition** nodes: Used to apply an operator to the entire document/table, e.g. the EXISTS operator in SQL. These types of nodes are _not used_ by any of our interpreters. - **Compound Condition** nodes: Used to apply an operator across N-many child nodes. - **Field Condition** nodes: Used to apply an operator to a field and an optional value. - ## Expanded Syntax -``` python +```python START := EXPRS EXPRS := COMPOUND_EXPR | FIELD_EXPR @@ -125,12 +124,12 @@ The `FIELD_NAME` corresponds to the field being referenced in the database. `COM ``` - ## Concise syntax UCAST supports an abbreviated "concise" syntax, which allows leaving out the often redundant "type" and "operation" fields from the nodes. It uses some implicit construction rules to make common collections of conditions easier to write. Two assumptions made in the concise format: + - The default compound operation is **and**. - The default field operation is **eq**. @@ -152,122 +151,122 @@ COMPOUND_OP_NAME := 'and' | 'or' | 'not' The `FIELD_NAME` corresponds to the field being referenced in the database. - ## Compound Operations The `not` operation is not generally supported by all clients. -Operation | `COMPOUND_OP_NAME` | Supported Types | [`@open-policy-agent/ucast-prisma`](https://github.com/open-policy-agent/opa-typescript/tree/main/packages/ucast-prisma) | [`OpenPolicyAgent.Ucast.Linq`](https://github.com/open-policy-agent/ucast-linq) ----|---|---|---|--- -And | `and` | `array` | :white_check_mark: | :white_check_mark: -Or | `or` | `array` | :white_check_mark: | :white_check_mark: -Not | `not` | `array` with 1 entry | :white_check_mark: | :x: - +| Operation | `COMPOUND_OP_NAME` | Supported Types | [`@open-policy-agent/ucast-prisma`](https://github.com/open-policy-agent/opa-typescript/tree/main/packages/ucast-prisma) | [`OpenPolicyAgent.Ucast.Linq`](https://github.com/open-policy-agent/ucast-linq) | +| --------- | ------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------- | +| And | `and` | `array` | :white_check_mark: | :white_check_mark: | +| Or | `or` | `array` | :white_check_mark: | :white_check_mark: | +| Not | `not` | `array` with 1 entry | :white_check_mark: | :x: | ## Field Operations Not all **field operations** are supported by every database integration. The following is a (non-comprehensive) compatibility matrix for the EOPA supported UCAST interpreters. -Operation | `FIELD_OP_NAME` | Supported `VALUE` Types | [`@open-policy-agent/ucast-prisma`](https://github.com/open-policy-agent/opa-typescript/tree/main/packages/ucast-prisma) | [`OpenPolicyAgent.Ucast.Linq`](https://github.com/open-policy-agent/ucast-linq) ----|---|---|---|--- -Equals | `eq` | `string`, `number`, `boolean`, `null` | :white_check_mark: | :white_check_mark: -Not Equals | `ne` | `string`, `number`, `boolean`, `null` | :white_check_mark: | :white_check_mark: -Less Than | `lt` | `number` | :white_check_mark: | :white_check_mark: -Less Than or Equals | `lte` | `number` | :white_check_mark: | :white_check_mark: -Greater Than | `gt` | `number` | :white_check_mark: | :white_check_mark: -Greater Than or Equals | `gte` | `number` | :white_check_mark: | :white_check_mark: -In | `in` | `array` | :white_check_mark: | :white_check_mark: -Not In | `nin` | `array` | :white_check_mark: | :white_check_mark: -Contains | `contains` | `string`, `number`, `boolean` | :white_check_mark: | :x: -Starts With | `startswith` | `string` | :white_check_mark: | :x: -Ends With | `endswith` | `string` | :white_check_mark: | :x: - +| Operation | `FIELD_OP_NAME` | Supported `VALUE` Types | [`@open-policy-agent/ucast-prisma`](https://github.com/open-policy-agent/opa-typescript/tree/main/packages/ucast-prisma) | [`OpenPolicyAgent.Ucast.Linq`](https://github.com/open-policy-agent/ucast-linq) | +| ---------------------- | --------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------- | +| Equals | `eq` | `string`, `number`, `boolean`, `null` | :white_check_mark: | :white_check_mark: | +| Not Equals | `ne` | `string`, `number`, `boolean`, `null` | :white_check_mark: | :white_check_mark: | +| Less Than | `lt` | `number` | :white_check_mark: | :white_check_mark: | +| Less Than or Equals | `lte` | `number` | :white_check_mark: | :white_check_mark: | +| Greater Than | `gt` | `number` | :white_check_mark: | :white_check_mark: | +| Greater Than or Equals | `gte` | `number` | :white_check_mark: | :white_check_mark: | +| In | `in` | `array` | :white_check_mark: | :white_check_mark: | +| Not In | `nin` | `array` | :white_check_mark: | :white_check_mark: | +| Contains | `contains` | `string`, `number`, `boolean` | :white_check_mark: | :x: | +| Starts With | `startswith` | `string` | :white_check_mark: | :x: | +| Ends With | `endswith` | `string` | :white_check_mark: | :x: | ## Examples - ### Simple: Product Prices Use case: Show products with a price less than or equal to $500 Expanded Format: + ```json { - "type": "field", - "field": "products.price", - "operator": "lte", - "value": 500 + "type": "field", + "field": "products.price", + "operator": "lte", + "value": 500 } ``` Concise Format: + ```json { - "products.price": { - "lte": 500 - } + "products.price": { + "lte": 500 + } } ``` - ### Compound: Support Tickets Use Case: Show tickets that are assigned to "Alice Zimmerman" and have a severity of 1 or 2. Expanded Format: + ```json { - "type": "compound", - "operator": "and", - "value": [ - { - "type": "field", - "field": "tickets.assignee", - "operator": "eq", - "value": "Alice Zimmerman" - }, - { - "type": "field", - "field": "tickets.severity", - "operator": "in", - "value": [1, 2] - } - ] + "type": "compound", + "operator": "and", + "value": [ + { + "type": "field", + "field": "tickets.assignee", + "operator": "eq", + "value": "Alice Zimmerman" + }, + { + "type": "field", + "field": "tickets.severity", + "operator": "in", + "value": [1, 2] + } + ] } ``` Concise Format: + ```json { - "tickets.assignee": "Alice Zimmerman", - "tickets.severity": { "in": [1, 2] }, + "tickets.assignee": "Alice Zimmerman", + "tickets.severity": { "in": [1, 2] } } ``` - ### Nots and Column Comparisons: Support Tickets Use Case: Show tickets where the assignee is not the resolver. Expanded Format: + ```json { - "type": "compound", - "operator": "not", - "value": [ - { - "type": "field", - "field": "tickets.assignee", - "operator": "eq", - "value": { "field": "tickets.resolver" } - } - ] + "type": "compound", + "operator": "not", + "value": [ + { + "type": "field", + "field": "tickets.assignee", + "operator": "eq", + "value": { "field": "tickets.resolver" } + } + ] } ``` Concise Format: + ```json { - "not": [{"tickets.assignee": {"field": "tickets.resolver"}}] + "not": [{ "tickets.assignee": { "field": "tickets.resolver" } }] } ``` diff --git a/docs/docs/kubernetes/index.md b/docs/docs/kubernetes/index.md index f00451be95..e614ca37fc 100644 --- a/docs/docs/kubernetes/index.md +++ b/docs/docs/kubernetes/index.md @@ -278,8 +278,7 @@ See the [Policy Authoring](./kubernetes/primer) and [Tutorial: Ingress Validatio See the following pages on [kubernetes.io](https://kubernetes.io) for more information on admission control: -- [A Guide to Kubernetes Admission - Controllers](https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/) +- [A Guide to Kubernetes Admission Controllers](https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/) for a quick primer on admission controllers. - [Dynamic Admission Control](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/) for details on configuring external admission controllers. diff --git a/docs/docs/ocp/api-reference.md b/docs/docs/ocp/api-reference.md index 6e7102e8c4..804d68c320 100644 --- a/docs/docs/ocp/api-reference.md +++ b/docs/docs/ocp/api-reference.md @@ -194,7 +194,6 @@ Bundles are collections of policies and data that can be distributed to OPA inst {} ``` - ### `DELETE /v1/bundles/{bundle}` **Description**: Delete a bundle @@ -353,7 +352,6 @@ Sources define where policies and data come from (Git repositories, local files, {} ``` - ### `DELETE /v1/sources/{source}` **Description**: Delete a source @@ -566,7 +564,6 @@ Stacks define how bundles are distributed to different environments or services {} ``` - ### `DELETE /v1/stacks/{stack}` **Description**: Delete a stack @@ -618,7 +615,7 @@ As a rule, the HTTP API will **never return** a secret value, it only allows aut ```json { - "result": "api-token" + "result": "api-token" } ``` @@ -653,7 +650,6 @@ As a rule, the HTTP API will **never return** a secret value, it only allows aut {} ``` - ### `DELETE /v1/secrets/{secret}` **Description**: Delete a secret diff --git a/docs/docs/ocp/concepts.md b/docs/docs/ocp/concepts.md index 902ced833d..4ee03dd6c4 100644 --- a/docs/docs/ocp/concepts.md +++ b/docs/docs/ocp/concepts.md @@ -560,4 +560,3 @@ loaded in lexical order and the last file to set a scalar or list value wins. If the –merge-conflict-fail argument is specified, then scalar and list values are never overridden and an error will be returned if two files set the same field to a different value. - diff --git a/docs/docs/ocp/guide-deploy-as-a-service.md b/docs/docs/ocp/guide-deploy-as-a-service.md index a889bbe134..69dca15db7 100644 --- a/docs/docs/ocp/guide-deploy-as-a-service.md +++ b/docs/docs/ocp/guide-deploy-as-a-service.md @@ -59,6 +59,7 @@ It uses the same configuration format as `opactl run`, see `opactl db migrate -- Notably, it comes with a `--dry-run` flag for _not actually applying_ the migrations. When OCP starts without `--apply-migrations`, it will + 1. warn if there are un-applied migrations known to the binary 2. warn if the binary appears to be stale (database's migration state is newer than the binary's migrations) 3. finally, attempt to use the database as-is. diff --git a/docs/docs/policy-language.md b/docs/docs/policy-language.md index 71330c2813..0388890c75 100644 --- a/docs/docs/policy-language.md +++ b/docs/docs/policy-language.md @@ -252,7 +252,7 @@ deny contains sprintf("User %s's location was '%s', but must be one of %v", [inp -In the above example, the `input.username` value is `undefined`; notice how +In the above example, the `input.username` value is `undefined`; notice how - the first `deny` rule uses string interpolation, and will output `User 's role was 'guest', but must be one of ["admin", "employee"]`, whereas - the second `deny` rule uses `sprintf`, and will output no result as it failed to evaluate even though `input.username` is inconsequential to the logic in the rule's body. diff --git a/docs/docs/policy-performance.md b/docs/docs/policy-performance.md index db34cad5e1..cce33bcd6a 100644 --- a/docs/docs/policy-performance.md +++ b/docs/docs/policy-performance.md @@ -416,8 +416,8 @@ why policy evaluation is slow. The `opa eval` command provides the following profiler options: -| Option | Detail | Default | -| ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | +| Option | Detail | Default | +| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | `--profile` | Enables expression profiling and outputs profiler results. | off | | `--profile-sort` | Criteria to sort the expression profiling results. This options implies `--profile`. | total_time_ns => num_eval => num_redo => num_gen_expr => file => line | | `--profile-limit` | Desired number of profiling results sorted on the given criteria. This options implies `--profile`. | 10 | @@ -741,8 +741,8 @@ to evaluate (loading, parsing, compiling, etc.) is omitted. #### Options for `opa bench` -| Option | Detail | Default | -| ------------------------------------------------------- | ------------------------------------------------- | ------- | +| Option | Detail | Default | +| ------------ | ------------------------------------------------- | ------- | | `--benchmem` | Report memory allocations with benchmark results. | true | | `--metrics` | Report additional query performance metrics. | true | | `--count` | Number of times to repeat the benchmark. | 1 | @@ -756,8 +756,8 @@ track relative time as policies change. #### Options for `opa test --bench` -| Option | Detail | Default | -| ------------------------------------------------------- | ------------------------------------------------- | ------- | +| Option | Detail | Default | +| ------------ | ------------------------------------------------- | ------- | | `--benchmem` | Report memory allocations with benchmark results. | true | | `--count` | Number of times to repeat the benchmark. | 1 | diff --git a/docs/docs/policy-reference/_examples/crypto/digest_verification/input.json b/docs/docs/policy-reference/_examples/crypto/digest_verification/input.json index 40d1b315d5..059ffafabc 100644 --- a/docs/docs/policy-reference/_examples/crypto/digest_verification/input.json +++ b/docs/docs/policy-reference/_examples/crypto/digest_verification/input.json @@ -1,7 +1,7 @@ { "payload": { "user": "alice", - "action": "read", + "action": "read", "resource": "/api/users" }, "expected_digest": "ea99819f665c10c744cbbf8da651c37a" diff --git a/docs/docs/policy-reference/_examples/crypto/digest_verification/intro.md b/docs/docs/policy-reference/_examples/crypto/digest_verification/intro.md index 81f56d4ab3..1fb96e950e 100644 --- a/docs/docs/policy-reference/_examples/crypto/digest_verification/intro.md +++ b/docs/docs/policy-reference/_examples/crypto/digest_verification/intro.md @@ -3,4 +3,3 @@ This example shows how to use `crypto.md5` to verify payload integrity by comput Content verification is helpful where you need to ensure data hasn't been tampered with or missed during transmission. The digest acts as a fingerprint - any change to the payload will result in a different digest. Change any value in the `payload` object (like the user name or resource path) and re-run the example. You'll see `digest_valid` becomes `false`, demonstrating how any change is detected. - diff --git a/docs/docs/policy-reference/_examples/encoding/envoy_header_manipulation/intro.md b/docs/docs/policy-reference/_examples/encoding/envoy_header_manipulation/intro.md index 7d04ea5b75..80324bf9c1 100644 --- a/docs/docs/policy-reference/_examples/encoding/envoy_header_manipulation/intro.md +++ b/docs/docs/policy-reference/_examples/encoding/envoy_header_manipulation/intro.md @@ -3,4 +3,3 @@ This example shows how `base64.encode` acts as a utility function to bridge comm Suppose that some legacy client sends credentials in custom headers (`x-username`, `x-password`), but the downstream service expects HTTP Basic Authentication. This example policy uses the base64 function to deliver this transparently to the downstream caller. This might be useful in an API gateway where you need to adapt between different authentication schemes without the option of editing clients and downstream servers. - diff --git a/docs/docs/policy-reference/_examples/io.jwt/decode_verify/cert/intro.md b/docs/docs/policy-reference/_examples/io.jwt/decode_verify/cert/intro.md index c07b27657c..e6e36485b0 100644 --- a/docs/docs/policy-reference/_examples/io.jwt/decode_verify/cert/intro.md +++ b/docs/docs/policy-reference/_examples/io.jwt/decode_verify/cert/intro.md @@ -1,4 +1,5 @@ + Some users may prefer to use a certificate to verify the JWT token. This example shows how to use a certificate to verify the JWT. Much like the other examples, it only checks the `iss` claim. diff --git a/docs/docs/policy-reference/_examples/io.jwt/decode_verify/jwks/intro.md b/docs/docs/policy-reference/_examples/io.jwt/decode_verify/jwks/intro.md index fd6a53a19f..74ce4eb762 100644 --- a/docs/docs/policy-reference/_examples/io.jwt/decode_verify/jwks/intro.md +++ b/docs/docs/policy-reference/_examples/io.jwt/decode_verify/jwks/intro.md @@ -1,4 +1,5 @@ + This example builds on the JWKS example above diff --git a/docs/docs/policy-reference/_examples/io.jwt/decode_verify/jwks_groups/intro.md b/docs/docs/policy-reference/_examples/io.jwt/decode_verify/jwks_groups/intro.md index 75b13a0a7f..c40de6015a 100644 --- a/docs/docs/policy-reference/_examples/io.jwt/decode_verify/jwks_groups/intro.md +++ b/docs/docs/policy-reference/_examples/io.jwt/decode_verify/jwks_groups/intro.md @@ -1,4 +1,5 @@ + So far, all the examples on this page have used the `constraints` parameter to specify the claims that should be checked and their values. The functionality covered by `constraints` represents the core checks when verifying a JWT token. diff --git a/docs/docs/policy-reference/_examples/io.jwt/decode_verify/jwks_time/intro.md b/docs/docs/policy-reference/_examples/io.jwt/decode_verify/jwks_time/intro.md index c8a6f65440..2bfda9430b 100644 --- a/docs/docs/policy-reference/_examples/io.jwt/decode_verify/jwks_time/intro.md +++ b/docs/docs/policy-reference/_examples/io.jwt/decode_verify/jwks_time/intro.md @@ -1,4 +1,5 @@ + In addition to verifying the JWT token's signature and issuer, this example also checks the token's validity period. The token in the example is valid for 2020-2030, try it out in the playground and use the example code diff --git a/docs/docs/policy-reference/_examples/io.jwt/decode_verify/symmetric/intro.md b/docs/docs/policy-reference/_examples/io.jwt/decode_verify/symmetric/intro.md index cdca09d217..527b147bde 100644 --- a/docs/docs/policy-reference/_examples/io.jwt/decode_verify/symmetric/intro.md +++ b/docs/docs/policy-reference/_examples/io.jwt/decode_verify/symmetric/intro.md @@ -1,4 +1,5 @@ + :::warning This example uses a symmetric key to verify the token. This is not recommended for production use. Please see the examples below using `JWKs` or PEM-encoded certificates more examples. diff --git a/docs/docs/policy-reference/_examples/regex/find_all_string_submatch_n/email_plus_addressing/intro.md b/docs/docs/policy-reference/_examples/regex/find_all_string_submatch_n/email_plus_addressing/intro.md index da43e0b1dd..7a94e7f775 100644 --- a/docs/docs/policy-reference/_examples/regex/find_all_string_submatch_n/email_plus_addressing/intro.md +++ b/docs/docs/policy-reference/_examples/regex/find_all_string_submatch_n/email_plus_addressing/intro.md @@ -1,4 +1,5 @@ + In the example that follows, we show a policy that uses the `regex.find_all_string_submatch_n` built-in to extract the 'plus suffix', if present, from an email address. diff --git a/docs/docs/policy-reference/_examples/regex/find_all_string_submatch_n/scope_parsing/intro.md b/docs/docs/policy-reference/_examples/regex/find_all_string_submatch_n/scope_parsing/intro.md index 88a0ac7dc1..5293f71d26 100644 --- a/docs/docs/policy-reference/_examples/regex/find_all_string_submatch_n/scope_parsing/intro.md +++ b/docs/docs/policy-reference/_examples/regex/find_all_string_submatch_n/scope_parsing/intro.md @@ -1,4 +1,5 @@ + Here we see how `regex.find_all_string_submatch_n` can be used to create structured data from unstructured text. In this example, we parse a list of scopes from a string and use that to create an object we can use in policies to diff --git a/docs/docs/policy-reference/_examples/regex/globs_match/role_patterns/intro.md b/docs/docs/policy-reference/_examples/regex/globs_match/role_patterns/intro.md index 0dfda7f768..f0f0c20ce7 100644 --- a/docs/docs/policy-reference/_examples/regex/globs_match/role_patterns/intro.md +++ b/docs/docs/policy-reference/_examples/regex/globs_match/role_patterns/intro.md @@ -1,4 +1,5 @@ + This example demonstrates using `regex.globs_match` in Rego to ensure actions are allowed only if the user's permissions overlap with the required permissions for the action. The user's permissions are defined by patterns, as are the diff --git a/docs/docs/policy-reference/_examples/regex/match/case-insensitive/intro.md b/docs/docs/policy-reference/_examples/regex/match/case-insensitive/intro.md index 69f0c36dff..ecb34813db 100644 --- a/docs/docs/policy-reference/_examples/regex/match/case-insensitive/intro.md +++ b/docs/docs/policy-reference/_examples/regex/match/case-insensitive/intro.md @@ -1,4 +1,5 @@ + Sometimes data can be supplied in a variety of cases, and matches need to be the same regardless of case. One example of this when matching GitHub usernames. diff --git a/docs/docs/policy-reference/_examples/regex/match/case-insensitive/outro.md b/docs/docs/policy-reference/_examples/regex/match/case-insensitive/outro.md index 46684578e7..29b30cf7dd 100644 --- a/docs/docs/policy-reference/_examples/regex/match/case-insensitive/outro.md +++ b/docs/docs/policy-reference/_examples/regex/match/case-insensitive/outro.md @@ -1,12 +1,13 @@ + :::tip Here are the common modifiers for regular expressions: -| Flag | Description | -|------|-------------------------------------------------------------------------------------| -| `i` | case-insensitive (default false) | -| `m` | multi-line mode: `^` and `$` match begin/end line in addition to begin/end text | -| `s` | let `.` match `\n` (default false) | +| Flag | Description | +| ---- | ------------------------------------------------------------------------------- | +| `i` | case-insensitive (default false) | +| `m` | multi-line mode: `^` and `$` match begin/end line in addition to begin/end text | +| `s` | let `.` match `\n` (default false) | Read more here on the [RE2 Wiki](https://github.com/google/re2/wiki/Syntax). ::: diff --git a/docs/docs/policy-reference/_examples/regex/match/email/intro.md b/docs/docs/policy-reference/_examples/regex/match/email/intro.md index cbdc06138d..de31cd0b88 100644 --- a/docs/docs/policy-reference/_examples/regex/match/email/intro.md +++ b/docs/docs/policy-reference/_examples/regex/match/email/intro.md @@ -1,4 +1,5 @@ + Validating emails with Regular Expressions is a common policy task. Email validation is more complicated than just checking an email matches a pattern, but since a Rego policy is often a first point of contact, doing a pattern based test on emails is diff --git a/docs/docs/policy-reference/_examples/regex/match/names/intro.md b/docs/docs/policy-reference/_examples/regex/match/names/intro.md index 07e29fc2c1..fd0a6b1959 100644 --- a/docs/docs/policy-reference/_examples/regex/match/names/intro.md +++ b/docs/docs/policy-reference/_examples/regex/match/names/intro.md @@ -1,4 +1,5 @@ + Text provided by users is often unstructured and untrusted. To ensure that the data is both safe to use and error-free, `regex.match()` can be used to validate the data against a simple pattern. diff --git a/docs/docs/policy-reference/_examples/regex/match/paths/intro.md b/docs/docs/policy-reference/_examples/regex/match/paths/intro.md index 18eb38268a..a7760fd8a2 100644 --- a/docs/docs/policy-reference/_examples/regex/match/paths/intro.md +++ b/docs/docs/policy-reference/_examples/regex/match/paths/intro.md @@ -1,4 +1,5 @@ + Managing access control in web applications is crucial for security. The following example uses Rego's `regex.match` to define role-based access to different URL paths. By associating URL patterns with user roles like "intern" diff --git a/docs/docs/policy-reference/_examples/regex/template_match/path_pattern/intro.md b/docs/docs/policy-reference/_examples/regex/template_match/path_pattern/intro.md index 8610730729..80befe89c0 100644 --- a/docs/docs/policy-reference/_examples/regex/template_match/path_pattern/intro.md +++ b/docs/docs/policy-reference/_examples/regex/template_match/path_pattern/intro.md @@ -1,4 +1,5 @@ + In the example that follows, we have a complex path which represents an AWS ARN owned by a project with a UUID v4 identifier. The path is validated in two parts using two separate patterns, each contained to particular segments of the diff --git a/docs/docs/policy-reference/_examples/rego/rule_metadata/input.json b/docs/docs/policy-reference/_examples/rego/rule_metadata/input.json index 4c1810cfc9..7ed685d809 100644 --- a/docs/docs/policy-reference/_examples/rego/rule_metadata/input.json +++ b/docs/docs/policy-reference/_examples/rego/rule_metadata/input.json @@ -1,7 +1,7 @@ { - "number": 11, - "subject": { - "name": "John doe", - "role": "customer" - } + "number": 11, + "subject": { + "name": "John doe", + "role": "customer" + } } diff --git a/docs/docs/policy-reference/_examples/strings/contains/email-validation/intro.md b/docs/docs/policy-reference/_examples/strings/contains/email-validation/intro.md index a468f1256f..1241e9c370 100644 --- a/docs/docs/policy-reference/_examples/strings/contains/email-validation/intro.md +++ b/docs/docs/policy-reference/_examples/strings/contains/email-validation/intro.md @@ -1,4 +1,5 @@ + In the example that follows, `contains` is used to test if the `@` symbol is contained in the supplied email address. This can be useful as a first check on raw user data. diff --git a/docs/docs/policy-reference/_examples/time/clock/local_business_hours/intro.md b/docs/docs/policy-reference/_examples/time/clock/local_business_hours/intro.md index 35d0d75c5f..4901def1fc 100644 --- a/docs/docs/policy-reference/_examples/time/clock/local_business_hours/intro.md +++ b/docs/docs/policy-reference/_examples/time/clock/local_business_hours/intro.md @@ -1,4 +1,5 @@ + A common attribute-based access control (ABAC) requirement is to grant access based on time. This is typically done by determining the user's local time and ensuring it falls within a given period. diff --git a/docs/docs/policy-reference/_examples/time/format/local_time/intro.md b/docs/docs/policy-reference/_examples/time/format/local_time/intro.md index 6a24142467..197199ec9f 100644 --- a/docs/docs/policy-reference/_examples/time/format/local_time/intro.md +++ b/docs/docs/policy-reference/_examples/time/format/local_time/intro.md @@ -1,4 +1,5 @@ + `time.format` can be used to provide information to the user in a human-readable format in error messages. Error codes and local times can be useful when debugging or troubleshooting diff --git a/docs/docs/policy-reference/_examples/time/now_ns/past/intro.md b/docs/docs/policy-reference/_examples/time/now_ns/past/intro.md index 4c78604b1d..e27dd347b7 100644 --- a/docs/docs/policy-reference/_examples/time/now_ns/past/intro.md +++ b/docs/docs/policy-reference/_examples/time/now_ns/past/intro.md @@ -1,4 +1,5 @@ + In this example, we see compare an [RFC3339](https://datatracker.ietf.org/doc/html/rfc3339) timestamp with the current time to determine if the timestamp is in the past. diff --git a/docs/docs/policy-reference/keywords/_examples/contains/aggregated-validation/intro.md b/docs/docs/policy-reference/keywords/_examples/contains/aggregated-validation/intro.md index 907d795241..96cfb5745f 100644 --- a/docs/docs/policy-reference/keywords/_examples/contains/aggregated-validation/intro.md +++ b/docs/docs/policy-reference/keywords/_examples/contains/aggregated-validation/intro.md @@ -1,4 +1,5 @@ + Using `contains` is commonly used to create validation messages from performing a series of checks on an object. In this example, if there are any `failures` then `allow` will be false. Using `contains` diff --git a/docs/docs/policy-reference/keywords/_examples/contains/object-validation/intro.md b/docs/docs/policy-reference/keywords/_examples/contains/object-validation/intro.md index 99e6ee8e22..176c6ef6e7 100644 --- a/docs/docs/policy-reference/keywords/_examples/contains/object-validation/intro.md +++ b/docs/docs/policy-reference/keywords/_examples/contains/object-validation/intro.md @@ -1,4 +1,5 @@ + Using `contains` is also useful when building up more complicated data structures in policies. In this example, `contains` is used to set validation errors that are grouped by the item they refer to. diff --git a/docs/docs/policy-reference/keywords/_examples/contains/todo-list/intro.md b/docs/docs/policy-reference/keywords/_examples/contains/todo-list/intro.md index 49ec81674f..c9540ae815 100644 --- a/docs/docs/policy-reference/keywords/_examples/contains/todo-list/intro.md +++ b/docs/docs/policy-reference/keywords/_examples/contains/todo-list/intro.md @@ -1,4 +1,5 @@ + While this first example is trivially simple and unlikely to be useful when building real policies, it illustrates the fundamental reason for using the `contains` keyword: building sets. Sets are unordered collections, and they form an important building block for many policies. diff --git a/docs/docs/policy-reference/keywords/_examples/default/deny/intro.md b/docs/docs/policy-reference/keywords/_examples/default/deny/intro.md index fa4a81bcd4..74cccebe43 100644 --- a/docs/docs/policy-reference/keywords/_examples/default/deny/intro.md +++ b/docs/docs/policy-reference/keywords/_examples/default/deny/intro.md @@ -1,4 +1,5 @@ + When default deny behavior is required, knowing that a value will never be undefined is helpful. This is common in access control systems where access is denied unless explicitly allowed. diff --git a/docs/docs/policy-reference/keywords/_examples/default/overrides/intro.md b/docs/docs/policy-reference/keywords/_examples/default/overrides/intro.md index 3ea08f2b1f..3ff883e17a 100644 --- a/docs/docs/policy-reference/keywords/_examples/default/overrides/intro.md +++ b/docs/docs/policy-reference/keywords/_examples/default/overrides/intro.md @@ -1,4 +1,5 @@ + As we saw in the previous example, `default` is helpful for handling undefined values. Handling undefined values is not just important for callers, but also within policies themselves. diff --git a/docs/docs/policy-reference/keywords/_examples/if/boolean/intro.md b/docs/docs/policy-reference/keywords/_examples/if/boolean/intro.md index 036c8e2c0b..0a5c9cd93a 100644 --- a/docs/docs/policy-reference/keywords/_examples/if/boolean/intro.md +++ b/docs/docs/policy-reference/keywords/_examples/if/boolean/intro.md @@ -1,4 +1,5 @@ + Most commonly, `if` is used to create boolean rules where if any rule head is true, then the whole rule is true. In this simple example, when both: diff --git a/docs/docs/policy-reference/keywords/_examples/if/functions/intro.md b/docs/docs/policy-reference/keywords/_examples/if/functions/intro.md index 9d657731cd..d2bb835d9a 100644 --- a/docs/docs/policy-reference/keywords/_examples/if/functions/intro.md +++ b/docs/docs/policy-reference/keywords/_examples/if/functions/intro.md @@ -1,4 +1,5 @@ + `if` is also used in functions. Much like rules, in Rego functions can have one or more heads. The head and body of a function are also separated by the `if` keyword for consistency and readability. diff --git a/docs/docs/policy-reference/keywords/_examples/if/multi-value/intro.md b/docs/docs/policy-reference/keywords/_examples/if/multi-value/intro.md index 5c4970a66a..465899be61 100644 --- a/docs/docs/policy-reference/keywords/_examples/if/multi-value/intro.md +++ b/docs/docs/policy-reference/keywords/_examples/if/multi-value/intro.md @@ -1,3 +1,4 @@ + The `if` keyword is used for all rules though, including rules that create objects and sets. diff --git a/docs/docs/policy-reference/keywords/_examples/if/when-not/intro.md b/docs/docs/policy-reference/keywords/_examples/if/when-not/intro.md index 180433ebd6..45693359c8 100644 --- a/docs/docs/policy-reference/keywords/_examples/if/when-not/intro.md +++ b/docs/docs/policy-reference/keywords/_examples/if/when-not/intro.md @@ -1,3 +1,4 @@ + `if` is _everywhere_ in Rego, but there are some cases where we don't use it. In this example, using `if` for a rule name is a parse error. diff --git a/docs/docs/policy-reference/keywords/_examples/some/some-in-object/intro.md b/docs/docs/policy-reference/keywords/_examples/some/some-in-object/intro.md index b89d08896b..e3f51a1095 100644 --- a/docs/docs/policy-reference/keywords/_examples/some/some-in-object/intro.md +++ b/docs/docs/policy-reference/keywords/_examples/some/some-in-object/intro.md @@ -1,4 +1,5 @@ + Similar to arrays, `some` can also be used on key->value pairs in objects. Here, we create two variables, one for the key and another for the value. The Rego rule is then evaluated for each pair. diff --git a/docs/docs/policy-reference/keywords/_examples/some/some-in/intro.md b/docs/docs/policy-reference/keywords/_examples/some/some-in/intro.md index 3c7e699b36..a09383a9cd 100644 --- a/docs/docs/policy-reference/keywords/_examples/some/some-in/intro.md +++ b/docs/docs/policy-reference/keywords/_examples/some/some-in/intro.md @@ -1,4 +1,5 @@ + In this example, we use `some` to select each item in an array, perform a check on it, and return matching items as a new array. Processing lists of values like this is one of the most common use diff --git a/docs/docs/rest-api.md b/docs/docs/rest-api.md index 8971899d46..510814e7c6 100644 --- a/docs/docs/rest-api.md +++ b/docs/docs/rest-api.md @@ -1608,7 +1608,6 @@ The following table summarizes the behavior for partial evaluation results. > The partially evaluated queries are represented as strings in the table above. The actual API response contains the JSON AST representation. - ### Compling a Rego policy (and query) into data filters ```http @@ -1619,15 +1618,13 @@ Content-Type: application/json Where the `{path}` is the slash delimited filter rule to be compiled. E.g., to compile the `data.filters.include` rule, query `/v1/compile/filters/include` - #### Request Headers -| Name | Required | Accepted Values | Description | -| --- | --- | --- | --- | -| Content-Type | No | `application/json` | Indicates the request body is either a JSON encoded document. | -| Content-Encoding | No | gzip | Indicates the request body is a compressed gzip object. | -| Accept | Yes | See [below](#accept-header--controlling-the-target-response-format) | See [below](#accept-header--controlling-the-target-response-format) | - +| Name | Required | Accepted Values | Description | +| ---------------- | -------- | ------------------------------------------------------------------- | ------------------------------------------------------------------- | +| Content-Type | No | `application/json` | Indicates the request body is either a JSON encoded document. | +| Content-Encoding | No | gzip | Indicates the request body is a compressed gzip object. | +| Accept | Yes | See [below](#accept-header--controlling-the-target-response-format) | See [below](#accept-header--controlling-the-target-response-format) | #### Accept Header – Controlling the Target Response Format @@ -1635,25 +1632,23 @@ The same request can generate filters that are representable in many different w OPA uses the `Accept` header to denote the target response format. -| Value | Response Schema | Description | -| --- | --- | -- | -| Multitarget: `application/vnd.opa.multitarget+json` | `result.{ucast,sqlserver,mysql,postgresql,sqlite}` | The partially evaluated result of the query in each target dialect. Use the `options.targetDialects` field in the request body to control targets. | -| UCAST: `application/vnd.opa.ucast.all+json`, `application/vnd.opa.ucast.minimal+json`, `application/vnd.opa.ucast.linq+json`, `application/vnd.opa.ucast.prisma+json` | `result.query`| UCAST JSON object describing the conditions under which the query is true. | -| SQL: `application/vnd.opa.sql.sqlserver+json`, `application/vnd.opa.sql.mysql+json`, `application/vnd.opa.sql.postgresql+json`, `application/vnd.opa.sql.sqlite+json` | `result.query`| String representing the SQL equivalent of the conditions under which the query is true. | - +| Value | Response Schema | Description | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| Multitarget: `application/vnd.opa.multitarget+json` | `result.{ucast,sqlserver,mysql,postgresql,sqlite}` | The partially evaluated result of the query in each target dialect. Use the `options.targetDialects` field in the request body to control targets. | +| UCAST: `application/vnd.opa.ucast.all+json`, `application/vnd.opa.ucast.minimal+json`, `application/vnd.opa.ucast.linq+json`, `application/vnd.opa.ucast.prisma+json` | `result.query` | UCAST JSON object describing the conditions under which the query is true. | +| SQL: `application/vnd.opa.sql.sqlserver+json`, `application/vnd.opa.sql.mysql+json`, `application/vnd.opa.sql.postgresql+json`, `application/vnd.opa.sql.sqlite+json` | `result.query` | String representing the SQL equivalent of the conditions under which the query is true. | #### Request Body -| Field | Type | Required | Description | -| --- | --- | --- | --- | -| `input` | `any` | No | The input document to use during partial evaluation and during mask rule evaluation (default: undefined). | -| `options` | `object[string, any]` | No | Additional options to use during partial evaluation | -| `options.disableInlining` | `array[string]` | No. Default: undefined | A list of rule references. | -| `options.maskRule` | `string` | No | The rule to evaluate for generating column masks. Overrides any `mask_rule` annotations defined in the policy. | -| `options.targetDialects` | `array[string]`, one of `ucast+all`, `ucast+minimal`, `ucast+prisma`, `ucast+linq`, `sql+sqlserver`, `sql+mysql`, `sql+postgresql` | Yes, if using `multitarget`. **Ignored for all other targets** | The output targets for partial evaluation. Different targets will have different constraints. Use [`Accept` header](#accept-header--controlling-the-target-response-format) to request a single compilation target. | -| `options.targetSQLTableMappings` | `object[string, object[string, string]]` | No | A mapping between tables and columns. See the [example](#example-mapping-table-and-column-names) for the schema. | -| `unknowns` | `array[string]` | No | The terms to treat as unknown during partial evaluation (default: `[]`). | - +| Field | Type | Required | Description | +| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `input` | `any` | No | The input document to use during partial evaluation and during mask rule evaluation (default: undefined). | +| `options` | `object[string, any]` | No | Additional options to use during partial evaluation | +| `options.disableInlining` | `array[string]` | No. Default: undefined | A list of rule references. | +| `options.maskRule` | `string` | No | The rule to evaluate for generating column masks. Overrides any `mask_rule` annotations defined in the policy. | +| `options.targetDialects` | `array[string]`, one of `ucast+all`, `ucast+minimal`, `ucast+prisma`, `ucast+linq`, `sql+sqlserver`, `sql+mysql`, `sql+postgresql` | Yes, if using `multitarget`. **Ignored for all other targets** | The output targets for partial evaluation. Different targets will have different constraints. Use [`Accept` header](#accept-header--controlling-the-target-response-format) to request a single compilation target. | +| `options.targetSQLTableMappings` | `object[string, object[string, string]]` | No | A mapping between tables and columns. See the [example](#example-mapping-table-and-column-names) for the schema. | +| `unknowns` | `array[string]` | No | The terms to treat as unknown during partial evaluation (default: `[]`). | #### Example Request @@ -1688,7 +1683,6 @@ Accept: application/vnd.opa.sql.postgresql+json } ``` - #### Example Response ```http @@ -1704,7 +1698,6 @@ Content-Type: application/vnd.opa.sql.postgresql+json } ``` - #### Unconditional Results from Filters Generation An absent `query` in the `result` indicates **unconditional deny**: @@ -1725,7 +1718,6 @@ An empty string `query` indicates **unconditional include**: } ``` - #### Example: Mapping Table and Column Names For this example, let's assume OPA is running with this policy: @@ -1773,7 +1765,6 @@ Accept: application/vnd.opa.sql.postgresql+json For multi-target requests, per-target replacementes are possible, since the SQL table names might not match what you need for a UCAST consumer library. - ## Health API The `/health` API endpoint executes a simple built-in policy query to verify diff --git a/docs/docs/wasm.md b/docs/docs/wasm.md index dd1d6ad8db..d0913e3248 100644 --- a/docs/docs/wasm.md +++ b/docs/docs/wasm.md @@ -146,31 +146,31 @@ Note the `i32=1` of `global[1]`, exported by the name of `opa_wasm_abi_version`. The primary exported functions for interacting with policy modules are listed below. In the ABI column, you can find the ABI version with which the export was introduced. -| Function | Description | ABI | -| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- | -| `eval` |
`int32 eval(ctx_addr)`
Evaluates the loaded policy with the provided evaluation context. The return value is reserved for future use.
| 1.0 | -| `builtins` |
`value_addr builtins(void)`
Returns the address of a mapping of built-in function names to numeric identifiers that are required by the policy.
| 1.0 | -| `entrypoints` |
`value_addr entrypoints(void)`
Returns the address of a mapping of entrypoints to numeric identifiers that can be selected when evaluating the policy.
| 1.0 | -| `opa_eval_ctx_new` |
`ctx_addr opa_eval_ctx_new(void)`
Returns the address of a newly allocated evaluation context.
| 1.0 | -| `opa_eval_ctx_set_input` |
`void opa_eval_ctx_set_input(ctx_addr, value_addr)`
Set the input value to use during evaluation. This must be called before each `eval()` call. If the input value is not set before evaluation, references to the `input` document result produce no results (i.e., they are undefined.)
| 1.0 | -| `opa_eval_ctx_set_data` |
`void opa_eval_ctx_set_data(ctx_addr, value_addr)`
Set the data value to use during evaluation. This should be called before each `eval()` call. If the data value is not set before evaluation, references to base `data` documents produce no results (i.e., they are undefined.)
| 1.0 | -| `opa_eval_ctx_set_entrypoint` |
`void opa_eval_ctx_set_entrypoint(ctx_addr, entrypoint_id)`
Set the entrypoint to evaluate. By default, entrypoint with id `0` is evaluated.
| 1.0 | -| `opa_eval_ctx_get_result` |
`value_addr opa_eval_ctx_get_result(ctx_addr)`
Get the result set produced by the evaluation process.
| 1.0 | -| `opa_malloc` |
`addr opa_malloc(int32 size)`
Allocates size bytes in the shared memory and returns the starting address.
| 1.0 | -| `opa_free` |
`void opa_free(addr)`
Free a pointer. Calls `opa_abort` on error.
| 1.0 | -| `opa_json_parse` |
`value_addr opa_json_parse(str_addr, size)`
Parses the JSON serialized value starting at str_addr of size bytes and returns the address of the parsed value. The parsed value may refer to a null, boolean, number, string, array, or object value.
| 1.0 | -| `opa_value_parse` |
`value_addr opa_value_parse(str_addr, size)`
The same as `opa_json_parse` except Rego set literals are supported.
| 1.0 | -| `opa_json_dump` |
`str_addr opa_json_dump(value_addr)`
Dumps the value referred to by `value_addr` to a null-terminated JSON serialized string and returns the address of the start of the string. Rego sets are serialized as JSON arrays. Non-string Rego object keys are serialized as strings.
| 1.0 | -| `opa_value_dump` |
`str_addr opa_value_dump(value_addr)`
The same as `opa_json_dump` except Rego sets are serialized using the literal syntax and non-string Rego object keys are not serialized as strings.
| 1.0 | -| `opa_heap_ptr_set` |
`void opa_heap_ptr_set(addr)`
Set the heap pointer for the next evaluation.
| 1.0 | -| `opa_heap_ptr_get` |
`addr opa_heap_ptr_get(void)`
Get the current heap pointer.
| 1.0 | +| Function | Description | ABI | +| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- | +| `eval` |
`int32 eval(ctx_addr)`
Evaluates the loaded policy with the provided evaluation context. The return value is reserved for future use.
| 1.0 | +| `builtins` |
`value_addr builtins(void)`
Returns the address of a mapping of built-in function names to numeric identifiers that are required by the policy.
| 1.0 | +| `entrypoints` |
`value_addr entrypoints(void)`
Returns the address of a mapping of entrypoints to numeric identifiers that can be selected when evaluating the policy.
| 1.0 | +| `opa_eval_ctx_new` |
`ctx_addr opa_eval_ctx_new(void)`
Returns the address of a newly allocated evaluation context.
| 1.0 | +| `opa_eval_ctx_set_input` |
`void opa_eval_ctx_set_input(ctx_addr, value_addr)`
Set the input value to use during evaluation. This must be called before each `eval()` call. If the input value is not set before evaluation, references to the `input` document result produce no results (i.e., they are undefined.)
| 1.0 | +| `opa_eval_ctx_set_data` |
`void opa_eval_ctx_set_data(ctx_addr, value_addr)`
Set the data value to use during evaluation. This should be called before each `eval()` call. If the data value is not set before evaluation, references to base `data` documents produce no results (i.e., they are undefined.)
| 1.0 | +| `opa_eval_ctx_set_entrypoint` |
`void opa_eval_ctx_set_entrypoint(ctx_addr, entrypoint_id)`
Set the entrypoint to evaluate. By default, entrypoint with id `0` is evaluated.
| 1.0 | +| `opa_eval_ctx_get_result` |
`value_addr opa_eval_ctx_get_result(ctx_addr)`
Get the result set produced by the evaluation process.
| 1.0 | +| `opa_malloc` |
`addr opa_malloc(int32 size)`
Allocates size bytes in the shared memory and returns the starting address.
| 1.0 | +| `opa_free` |
`void opa_free(addr)`
Free a pointer. Calls `opa_abort` on error.
| 1.0 | +| `opa_json_parse` |
`value_addr opa_json_parse(str_addr, size)`
Parses the JSON serialized value starting at str_addr of size bytes and returns the address of the parsed value. The parsed value may refer to a null, boolean, number, string, array, or object value.
| 1.0 | +| `opa_value_parse` |
`value_addr opa_value_parse(str_addr, size)`
The same as `opa_json_parse` except Rego set literals are supported.
| 1.0 | +| `opa_json_dump` |
`str_addr opa_json_dump(value_addr)`
Dumps the value referred to by `value_addr` to a null-terminated JSON serialized string and returns the address of the start of the string. Rego sets are serialized as JSON arrays. Non-string Rego object keys are serialized as strings.
| 1.0 | +| `opa_value_dump` |
`str_addr opa_value_dump(value_addr)`
The same as `opa_json_dump` except Rego sets are serialized using the literal syntax and non-string Rego object keys are not serialized as strings.
| 1.0 | +| `opa_heap_ptr_set` |
`void opa_heap_ptr_set(addr)`
Set the heap pointer for the next evaluation.
| 1.0 | +| `opa_heap_ptr_get` |
`addr opa_heap_ptr_get(void)`
Get the current heap pointer.
| 1.0 | | `opa_value_add_path` |
`int32 opa_value_add_path(base_value_addr, path_value_addr, value_addr)`
Add the value at the `value_addr` into the object referenced by `base_value_addr` at the given path. The `path_value_addr` must point to an array value with string keys (e.g.: `["a", "b", "c"]`). Existing values will be updated. On success the value at `value_addr` is no longer owned by the caller, it will be freed with the base value. The path value must be freed by the caller after use by calling `opa_value_free`. (The original path string passed to `opa_json_parse` or `opa_value_parse` to create the value must be freed by calling `opa_free`.) If an error occurs the base value will remain unchanged. Example: base object `{"a": {"b": 123}}`, path `["a", "x", "y"]`, and value `{"foo": "bar"}` will yield `{"a": {"b": 123, "x": {"y": {"foo": "bar"}}}}`. Returns an error code (see below).
| 1.0 | | `opa_value_remove_path` |
`int32 opa_value_remove_path(base_value_addr, path_value_addr)`
Remove the value from the object referenced by `base_value_addr` at the given path. Values removed will be freed. The path value must be freed by the caller after use by calling `opa_value_free`. (The original path string parsed by `opa_json_parse` or `opa_value_parse` must be released using `opa_free`.) The `path_value_addr` must point to an array value with string keys (e.g.: `["a", "b", "c"]`). Returns an error code (see below).
| 1.0 | -| `opa_value_free` |
`void opa_value_free(value_addr)`
Free a value such as one generated by `opa_value_parse` or `opa_json_parse` reference at `value_addr`
| 1.3 | -| `opa_heap_blocks_stash` |
`void opa_heap_blocks_stash(void)`
Stash free heap blocks in a shadow heap to enable `eval` or `opa_eval` to allocate only blocks that it can subsequently free with a call to `opa_heap_ptr_set`. The caller should subsequently call `opa_heap_ptr_get` and store the value to save before calling `opa_heap_bloks_restore`
| 1.3 | -| `opa_heap_blocks_restore` |
`void opa_heap_blocks_restore(void)`
Restore heap blocks stored by `opa_heap_blocks_stash` to the heap. This should only be called after a `opa_heap_ptr_set` to the a heap pointer recorded by `opa_heap_ptr_get` after the previous call to `opa_heap_blocks_stash`.
| 1.3 | -| `opa_heap_stash_clear` |
`void opa_heap_stash_clear(void)`
Drop all heap blocks saved by `opa_heap_blocks_stash`. This leaks memory in the VM unless the caller subsequently invokes `opa_heap_ptr_set` to a value taken prior to calling `opa_heap_blocks_stash`. (see below)
| 1.3 | -| `opa_eval` |
`str_addr opa_eval(_ addr, entrypoint_id int32, data value_addr, input str_addr, input_len int32, heap_ptr addr, format int32)`
One-off policy evaluation method. Its arguments are everything needed to evaluate: entrypoint, address of data in memory, address and length of input JSON string in memory, heap address to use, and the output format (`0` is JSON, `1` is "value", i.e. serialized Rego values). The first argument is reserved for future use and must be `0`. Returns the address to the serialised result value.
| 1.2 | +| `opa_value_free` |
`void opa_value_free(value_addr)`
Free a value such as one generated by `opa_value_parse` or `opa_json_parse` reference at `value_addr`
| 1.3 | +| `opa_heap_blocks_stash` |
`void opa_heap_blocks_stash(void)`
Stash free heap blocks in a shadow heap to enable `eval` or `opa_eval` to allocate only blocks that it can subsequently free with a call to `opa_heap_ptr_set`. The caller should subsequently call `opa_heap_ptr_get` and store the value to save before calling `opa_heap_bloks_restore`
| 1.3 | +| `opa_heap_blocks_restore` |
`void opa_heap_blocks_restore(void)`
Restore heap blocks stored by `opa_heap_blocks_stash` to the heap. This should only be called after a `opa_heap_ptr_set` to the a heap pointer recorded by `opa_heap_ptr_get` after the previous call to `opa_heap_blocks_stash`.
| 1.3 | +| `opa_heap_stash_clear` |
`void opa_heap_stash_clear(void)`
Drop all heap blocks saved by `opa_heap_blocks_stash`. This leaks memory in the VM unless the caller subsequently invokes `opa_heap_ptr_set` to a value taken prior to calling `opa_heap_blocks_stash`. (see below)
| 1.3 | +| `opa_eval` |
`str_addr opa_eval(_ addr, entrypoint_id int32, data value_addr, input str_addr, input_len int32, heap_ptr addr, format int32)`
One-off policy evaluation method. Its arguments are everything needed to evaluate: entrypoint, address of data in memory, address and length of input JSON string in memory, heap address to use, and the output format (`0` is JSON, `1` is "value", i.e. serialized Rego values). The first argument is reserved for future use and must be `0`. Returns the address to the serialised result value.
| 1.2 | The addresses passed and returned by the policy modules are 32-bit integer offsets into the shared memory region. The `value_addr` parameters and return @@ -192,10 +192,10 @@ OPA Wasm Error codes are int32 values defined as: Policy modules require the following function imports at instantiation-time: -| Namespace | Name | Params | Result | Description | -| --------- | -------------- | ------------------------------------------------------------------------------ | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `env` | `opa_abort` | `(addr)` | `void` | Called if an internal error occurs. The `addr` refers to a null-terminated string in the shared memory buffer. | -| `env` | `opa_println` | `(addr)` | `void` | Called to emit a message from the policy evaluation. The `addr` refers to a null-terminated string in the shared memory buffer. | +| Namespace | Name | Params | Result | Description | +| --------- | -------------- | ----------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `env` | `opa_abort` | `(addr)` | `void` | Called if an internal error occurs. The `addr` refers to a null-terminated string in the shared memory buffer. | +| `env` | `opa_println` | `(addr)` | `void` | Called to emit a message from the policy evaluation. The `addr` refers to a null-terminated string in the shared memory buffer. | | `env` | `opa_builtin0` | `(builtin_id, ctx)` | `addr` | Called to dispatch the built-in function identified by the `builtin_id`. The `ctx` parameter reserved for future use. The result `addr` must refer to a value in the shared-memory buffer. The function accepts 0 arguments. | | `env` | `opa_builtin1` | `(builtin_id, ctx, _1)` | `addr` | Same as previous except the function accepts 1 argument. | | `env` | `opa_builtin2` | `(builtin_id, ctx, _1, _2)` | `addr` | Same as previous except the function accepts 2 arguments. | diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index cc832a5e04..415064804d 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -7,7 +7,7 @@ const path = require("path"); import { loadPages } from "./src/lib/ecosystem/loadPages.js"; import { loadRules } from "./src/lib/projects/regal/loadRules.js"; -import { loadSurveyEventData, loadSurveyQuestions, loadSurveyEventMetadata } from "./src/lib/surveys/loadSurveyData.js"; +import { loadSurveyEventData, loadSurveyEventMetadata, loadSurveyQuestions } from "./src/lib/surveys/loadSurveyData.js"; const baseUrl = "/"; @@ -320,7 +320,7 @@ The Linux Foundation has registered trademarks and uses trademarks. For a list o }; }, }), - async function ecosystemLanguagePageGen(context, options) { + async function ecosystemLanguagePageGen(context, _options) { return { name: "ecosystem-language-gen", async loadContent() { @@ -329,13 +329,13 @@ The Linux Foundation has registered trademarks and uses trademarks. For a list o }, async contentLoaded({ content, actions }) { - const { pagesByLanguage, languages } = content; + const { languages } = content; await Promise.all( Object.keys(languages).map(async (language) => { const routePath = path.join(baseUrl, `/ecosystem/by-language/${language}`); return actions.addRoute({ path: routePath, - component: require.resolve("./src/EcosystemLanguage.js"), + component: require.resolve("./src/EcosystemLanguage.jsx"), exact: true, modules: {}, customData: { language }, @@ -346,7 +346,7 @@ The Linux Foundation has registered trademarks and uses trademarks. For a list o }; }, - async function ecosystemFeaturePageGen(context, options) { + async function ecosystemFeaturePageGen(context, _options) { return { name: "ecosystem-feature-gen", async loadContent() { @@ -362,7 +362,7 @@ The Linux Foundation has registered trademarks and uses trademarks. For a list o const routePath = path.join(baseUrl, `/ecosystem/by-feature/${feature}`); return actions.addRoute({ path: routePath, - component: require.resolve("./src/EcosystemFeature.js"), + component: require.resolve("./src/EcosystemFeature.jsx"), exact: true, modules: {}, customData: { feature }, @@ -373,7 +373,7 @@ The Linux Foundation has registered trademarks and uses trademarks. For a list o }; }, - async function ecosystemData(context, options) { + async function ecosystemData(context, _options) { return { name: "ecosystem-data", @@ -405,7 +405,7 @@ The Linux Foundation has registered trademarks and uses trademarks. For a list o }; }, - async function builtinData(context, options) { + async function builtinData(_context, _options) { return { name: "builtin-data", @@ -425,7 +425,7 @@ The Linux Foundation has registered trademarks and uses trademarks. For a list o }; }, - async function ecosystemPagesGen(context, options) { + async function ecosystemPagesGen(context, _options) { return { name: "ecosystem-entries-pages-gen", async loadContent() { @@ -441,7 +441,7 @@ The Linux Foundation has registered trademarks and uses trademarks. For a list o const routePath = path.join(baseUrl, `/ecosystem/entry/${entry.id}`); return actions.addRoute({ path: routePath, - component: require.resolve("./src/EcosystemEntry.js"), + component: require.resolve("./src/EcosystemEntry.jsx"), exact: true, modules: {}, customData: { id: entry.id }, @@ -452,7 +452,7 @@ The Linux Foundation has registered trademarks and uses trademarks. For a list o }; }, - async function versionsData(context, options) { + async function versionsData(context, _options) { return { name: "versions-data", @@ -489,7 +489,7 @@ The Linux Foundation has registered trademarks and uses trademarks. For a list o }; }, - async function cliData(context, options) { + async function cliData(context, _options) { return { name: "cli-data", @@ -509,13 +509,13 @@ The Linux Foundation has registered trademarks and uses trademarks. For a list o }; }, - async function versionsPageGen(context, options) { + async function versionsPageGen(_context, _options) { return { name: "version-page-gen", - async contentLoaded({ content, actions }) { + async contentLoaded({ content: _content, actions }) { return actions.addRoute({ path: path.join(baseUrl, `/docs/archive`), - component: require.resolve("./src/Archive.js"), + component: require.resolve("./src/Archive.jsx"), exact: true, modules: {}, }); @@ -523,7 +523,7 @@ The Linux Foundation has registered trademarks and uses trademarks. For a list o }; }, - async function ecosystemData(context, options) { + async function regalData(_context, _options) { return { name: "regal", @@ -539,19 +539,19 @@ The Linux Foundation has registered trademarks and uses trademarks. For a list o }; }, - async function surveyData(context, options) { + async function surveyData(context, _options) { return { name: "survey-data", async loadContent() { const eventData = await loadSurveyEventData( - path.join(context.siteDir, "src/data/surveys/events/**/**/data.json") + path.join(context.siteDir, "src/data/surveys/events/**/**/data.json"), ); const questions = await loadSurveyQuestions( - path.join(context.siteDir, "src/data/surveys/questions/**/data.json") + path.join(context.siteDir, "src/data/surveys/questions/**/data.json"), ); const eventMetadata = await loadSurveyEventMetadata( - path.join(context.siteDir, "src/data/surveys/events/**/metadata.json") + path.join(context.siteDir, "src/data/surveys/events/**/metadata.json"), ); return { eventData, questions, eventMetadata }; @@ -572,7 +572,7 @@ The Linux Foundation has registered trademarks and uses trademarks. For a list o const routePath = path.join(baseUrl, `/survey/${eventSlug}`); return addRoute({ path: routePath, - component: require.resolve("./src/SurveyEvent/index.js"), + component: require.resolve("./src/SurveyEvent/index.jsx"), exact: true, modules: {}, customData: { eventSlug }, diff --git a/docs/dprint.json b/docs/dprint.json new file mode 100644 index 0000000000..791bc2346d --- /dev/null +++ b/docs/dprint.json @@ -0,0 +1,20 @@ +{ + "lineWidth": 120, + "indentWidth": 2, + "useTabs": false, + "includes": ["**/*.{md,json,js,jsx,ts,tsx}"], + "excludes": [ + "**/node_modules", + "**/.docusaurus", + "**/build", + "**/package-lock.json", + "**/regal/**", + "**/style-guide.md", + "**/cheatsheet.md" + ], + "plugins": [ + "https://plugins.dprint.dev/markdown-0.17.8.wasm", + "https://plugins.dprint.dev/json-0.19.4.wasm", + "https://plugins.dprint.dev/typescript-0.93.0.wasm" + ] +} diff --git a/docs/eslint.config.mjs b/docs/eslint.config.mjs new file mode 100644 index 0000000000..a55267f0f5 --- /dev/null +++ b/docs/eslint.config.mjs @@ -0,0 +1,38 @@ +import js from "@eslint/js"; + +export default [ + js.configs.recommended, + { + languageOptions: { + ecmaVersion: "latest", + sourceType: "module", + globals: { + console: "readonly", + process: "readonly", + require: "readonly", + module: "readonly", + __dirname: "readonly", + __filename: "readonly", + window: "readonly", + document: "readonly", + navigator: "readonly", + URL: "readonly", + fetch: "readonly", + }, + }, + rules: { + "no-unused-vars": ["error", { argsIgnorePattern: "^_" }], + "no-console": "off", + }, + }, + { + ignores: [ + "node_modules/**", + ".docusaurus/**", + "build/**", + "projects/regal/**", + "src/theme/prism-rego.js", + "src/theme/prism-include-languages.js", + ], + }, +]; diff --git a/docs/functions/feedback.ts b/docs/functions/feedback.ts index c0748bab68..f3efa0eae7 100644 --- a/docs/functions/feedback.ts +++ b/docs/functions/feedback.ts @@ -88,4 +88,3 @@ export default async (req: Request, context: Context) => { }); } }; - diff --git a/docs/package-lock.json b/docs/package-lock.json index 33387b2146..d25959c134 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -17,12 +17,17 @@ "@easyops-cn/docusaurus-search-local": "^0.49.2", "@iconify/react": "^6.0.0", "@mermaid-js/layout-elk": "^0.1.9", + "eslint": "^9.39.2", "glob": "^11.0.3", + "markdownlint-cli": "^0.43.0", "md-front-matter": "^1.0.4", "raw-loader": "^4.0.2", "react-markdown": "^10.1.0", "recharts": "3.7.0" }, + "devDependencies": { + "baseline-browser-mapping": "^2.9.19" + }, "engines": { "node": ">=22.0.0" } @@ -4233,6 +4238,174 @@ "tslib": "^2.4.0" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/@eslint/js": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -4248,6 +4421,54 @@ "@hapi/hoek": "^9.0.0" } }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@iconify/react": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@iconify/react/-/react-6.0.0.tgz", @@ -6250,9 +6471,9 @@ } }, "node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", "peer": true, "bin": { @@ -6694,9 +6915,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.9.tgz", - "integrity": "sha512-hY/u2lxLrbecMEWSB0IpGzGyDyeoMFQhCvZd2jGFSE5I17Fh01sYUBPCJtkWERw7zrac9+cIghxm/ytJa2X8iA==", + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -8805,6 +9026,12 @@ "node": ">=4.0.0" } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "license": "MIT" + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -9358,6 +9585,66 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -9371,6 +9658,176 @@ "node": ">=8.0.0" } }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -9384,6 +9841,27 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -9746,6 +10224,12 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "license": "MIT" }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "license": "MIT" + }, "node_modules/fast-uri": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", @@ -9832,6 +10316,18 @@ "node": ">=0.8.0" } }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/file-loader": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", @@ -9988,6 +10484,25 @@ "flat": "cli.js" } }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "license": "ISC" + }, "node_modules/follow-redirects": { "version": "1.15.11", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", @@ -11652,6 +12167,12 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -11664,6 +12185,12 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "license": "MIT" + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -11676,6 +12203,15 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/katex": { "version": "0.16.22", "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.22.tgz", @@ -11804,6 +12340,19 @@ "node": ">=6" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -11822,6 +12371,15 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "license": "MIT" }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -11901,6 +12459,12 @@ "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", "license": "MIT" }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "license": "MIT" + }, "node_modules/lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -11989,6 +12553,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, "node_modules/markdown-table": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", @@ -11999,6 +12580,114 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/markdownlint-cli": { + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.43.0.tgz", + "integrity": "sha512-6vwurKK4B21eyYzwgX6ph13cZS7hE6LZfcS8QyD722CyxVD2RtAvbZK2p7k+FZbbKORulEuwl+hJaEq1l6/hoQ==", + "license": "MIT", + "dependencies": { + "commander": "~12.1.0", + "glob": "~11.0.0", + "ignore": "~6.0.2", + "js-yaml": "^4.1.0", + "jsonc-parser": "~3.3.1", + "jsonpointer": "5.0.1", + "markdownlint": "~0.36.1", + "minimatch": "~10.0.1", + "run-con": "~1.3.2", + "smol-toml": "~1.3.1" + }, + "bin": { + "markdownlint": "markdownlint.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/markdownlint-cli/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/markdownlint-cli/node_modules/glob": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", + "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.0.3", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/markdownlint-cli/node_modules/ignore": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-6.0.2.tgz", + "integrity": "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/markdownlint-cli/node_modules/markdownlint": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.36.1.tgz", + "integrity": "sha512-s73fU2CQN7WCgjhaQUQ8wYESQNzGRNOKDd+3xgVqu8kuTEhmwepd/mxOv1LR2oV046ONrTLBFsM7IoKWNvmy5g==", + "license": "MIT", + "dependencies": { + "markdown-it": "14.1.0", + "markdownlint-micromark": "0.1.12" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + } + }, + "node_modules/markdownlint-cli/node_modules/minimatch": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", + "license": "ISC", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/markdownlint-micromark": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.12.tgz", + "integrity": "sha512-RlB6EwMGgc0sxcIhOQ2+aq7Zw1V2fBnzbXKGgYK/mVWdT7cz34fteKSwfYeo4rL6+L/q2tyC9QtD/PgZbkdyJQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + } + }, "node_modules/marked": { "version": "16.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-16.3.0.tgz", @@ -12437,6 +13126,12 @@ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", "license": "CC0-1.0" }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "license": "MIT" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -14526,6 +15221,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "license": "MIT" + }, "node_modules/negotiator": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", @@ -14829,6 +15530,23 @@ "opener": "bin/opener-bin.js" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/p-cancelable": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", @@ -16700,6 +17418,15 @@ "postcss": "^8.4.31" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/pretty-error": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", @@ -16818,6 +17545,15 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/pupa": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", @@ -17937,6 +18673,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/run-con": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.3.2.tgz", + "integrity": "sha512-CcfE+mYiTcKEzg0IqS08+efdnH0oJ3zV0wSUFBNrMHMuxCtXvBCLzCJHatwuXDcu/RlhjTziTo/a1ruQik6/Yg==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~4.1.0", + "minimist": "^1.2.8", + "strip-json-comments": "~3.1.1" + }, + "bin": { + "run-con": "cli.js" + } + }, + "node_modules/run-con/node_modules/ini": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -18493,6 +19253,18 @@ "node": ">=8" } }, + "node_modules/smol-toml": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.3.4.tgz", + "integrity": "sha512-UOPtVuYkzYGee0Bd2Szz8d2G3RfMfJ2t3qVdZUAozZyAk+a0Sxa+QKix0YCwjL/A1RR0ar44nCxaoN9FxdJGwA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, "node_modules/snake-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", @@ -19140,6 +19912,18 @@ "license": "0BSD", "peer": true }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -19195,6 +19979,12 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, "node_modules/ufo": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", @@ -20274,6 +21064,15 @@ "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", "license": "MIT" }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", diff --git a/docs/package.json b/docs/package.json index 9333bfe8c5..90713f229a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -18,6 +18,7 @@ "@easyops-cn/docusaurus-search-local": "^0.49.2", "@iconify/react": "^6.0.0", "@mermaid-js/layout-elk": "^0.1.9", + "eslint": "^9.39.2", "glob": "^11.0.3", "md-front-matter": "^1.0.4", "raw-loader": "^4.0.2", @@ -26,5 +27,8 @@ }, "engines": { "node": ">=22.0.0" + }, + "devDependencies": { + "baseline-browser-mapping": "^2.9.19" } } diff --git a/docs/src/Archive.js b/docs/src/Archive.jsx similarity index 100% rename from docs/src/Archive.js rename to docs/src/Archive.jsx diff --git a/docs/src/EcosystemEntry.js b/docs/src/EcosystemEntry.jsx similarity index 100% rename from docs/src/EcosystemEntry.js rename to docs/src/EcosystemEntry.jsx diff --git a/docs/src/EcosystemFeature.js b/docs/src/EcosystemFeature.jsx similarity index 100% rename from docs/src/EcosystemFeature.js rename to docs/src/EcosystemFeature.jsx diff --git a/docs/src/EcosystemLanguage.js b/docs/src/EcosystemLanguage.jsx similarity index 100% rename from docs/src/EcosystemLanguage.js rename to docs/src/EcosystemLanguage.jsx diff --git a/docs/src/SurveyEvent/index.js b/docs/src/SurveyEvent/index.jsx similarity index 94% rename from docs/src/SurveyEvent/index.js rename to docs/src/SurveyEvent/index.jsx index 05aaa13e2e..fde8e60973 100644 --- a/docs/src/SurveyEvent/index.js +++ b/docs/src/SurveyEvent/index.jsx @@ -1,14 +1,14 @@ +import Link from "@docusaurus/Link"; +import Heading from "@theme/Heading"; import React, { useMemo } from "react"; import ReactMarkdown from "react-markdown"; -import Heading from "@theme/Heading"; -import Link from "@docusaurus/Link"; -import StandaloneLayout from "../components/StandaloneLayout"; import QuestionSingle from "../components/QuestionSingle"; +import StandaloneLayout from "../components/StandaloneLayout"; import allEventData from "@generated/survey-data/default/survey-event-data.json"; -import questions from "@generated/survey-data/default/survey-questions.json"; import eventMetadata from "@generated/survey-data/default/survey-event-metadata.json"; +import questions from "@generated/survey-data/default/survey-questions.json"; import styles from "./styles.module.css"; @@ -39,7 +39,7 @@ export default function SurveyEvent(props) { const groupedQuestions = useMemo(() => { const groups = questionIds.reduce((acc, questionId) => { const question = questions[questionId]; - const tag = question?.tags?.[0] || 'uncategorized'; + const tag = question?.tags?.[0] || "uncategorized"; (acc[tag] = acc[tag] || []).push(questionId); return acc; }, {}); @@ -55,12 +55,11 @@ export default function SurveyEvent(props) { const { tagOrder, tagDisplayNames, tagDescriptions } = useMemo(() => { const order = metadata?.sections?.map(s => s.tag) || Object.keys(groupedQuestions); const displayNames = { - uncategorized: 'Other', - ...metadata?.sections?.reduce((acc, s) => ({ ...acc, [s.tag]: s.title }), {}) + uncategorized: "Other", + ...metadata?.sections?.reduce((acc, s) => ({ ...acc, [s.tag]: s.title }), {}), }; const descriptions = metadata?.sections?.reduce((acc, s) => - s.description ? { ...acc, [s.tag]: s.description } : acc - , {}) || {}; + s.description ? { ...acc, [s.tag]: s.description } : acc, {}) || {}; return { tagOrder: order, tagDisplayNames: displayNames, tagDescriptions: descriptions }; }, [metadata, groupedQuestions]); @@ -95,8 +94,7 @@ export default function SurveyEvent(props) { {metadata.intro} {metadata?.blog && ( <> - {" "}These results were originally presented in the following{" "} - blog post. + {" "}These results were originally presented in the following blog post. )}

diff --git a/docs/src/components/BuiltinLegacyRedirect/index.js b/docs/src/components/BuiltinLegacyRedirect/index.jsx similarity index 100% rename from docs/src/components/BuiltinLegacyRedirect/index.js rename to docs/src/components/BuiltinLegacyRedirect/index.jsx diff --git a/docs/src/components/BuiltinSearch/index.js b/docs/src/components/BuiltinSearch/index.jsx similarity index 100% rename from docs/src/components/BuiltinSearch/index.js rename to docs/src/components/BuiltinSearch/index.jsx diff --git a/docs/src/components/BuiltinTable/index.js b/docs/src/components/BuiltinTable/index.jsx similarity index 100% rename from docs/src/components/BuiltinTable/index.js rename to docs/src/components/BuiltinTable/index.jsx diff --git a/docs/src/components/Card/index.js b/docs/src/components/Card/index.jsx similarity index 100% rename from docs/src/components/Card/index.js rename to docs/src/components/Card/index.jsx diff --git a/docs/src/components/CardGrid/index.js b/docs/src/components/CardGrid/index.jsx similarity index 93% rename from docs/src/components/CardGrid/index.js rename to docs/src/components/CardGrid/index.jsx index ddc7583928..7eb6d1e115 100644 --- a/docs/src/components/CardGrid/index.js +++ b/docs/src/components/CardGrid/index.jsx @@ -4,7 +4,7 @@ import styles from "./styles.module.css"; export default function CardGrid({ children, justifyCenter = true }) { return ( -
+
{children}
); diff --git a/docs/src/components/CommandDoc/index.js b/docs/src/components/CommandDoc/index.jsx similarity index 100% rename from docs/src/components/CommandDoc/index.js rename to docs/src/components/CommandDoc/index.jsx diff --git a/docs/src/components/CommandList/index.js b/docs/src/components/CommandList/index.jsx similarity index 100% rename from docs/src/components/CommandList/index.js rename to docs/src/components/CommandList/index.jsx diff --git a/docs/src/components/EcosystemEmbed/index.js b/docs/src/components/EcosystemEmbed/index.jsx similarity index 100% rename from docs/src/components/EcosystemEmbed/index.js rename to docs/src/components/EcosystemEmbed/index.jsx diff --git a/docs/src/components/EcosystemFeatureLink/index.js b/docs/src/components/EcosystemFeatureLink/index.jsx similarity index 100% rename from docs/src/components/EcosystemFeatureLink/index.js rename to docs/src/components/EcosystemFeatureLink/index.jsx diff --git a/docs/src/components/EvergreenCodeBlock/index.js b/docs/src/components/EvergreenCodeBlock/index.jsx similarity index 99% rename from docs/src/components/EvergreenCodeBlock/index.js rename to docs/src/components/EvergreenCodeBlock/index.jsx index 08cd8440b4..8837cb969b 100644 --- a/docs/src/components/EvergreenCodeBlock/index.js +++ b/docs/src/components/EvergreenCodeBlock/index.jsx @@ -49,4 +49,3 @@ function EvergreenCodeBlock({ children }) { } export default EvergreenCodeBlock; - diff --git a/docs/src/components/FeedbackForm/index.js b/docs/src/components/FeedbackForm/index.jsx similarity index 99% rename from docs/src/components/FeedbackForm/index.js rename to docs/src/components/FeedbackForm/index.jsx index bc2b1f9c7b..6518395a60 100644 --- a/docs/src/components/FeedbackForm/index.js +++ b/docs/src/components/FeedbackForm/index.jsx @@ -1,5 +1,5 @@ -import React, { useEffect, useState, useRef } from "react"; import { Icon } from "@iconify/react"; +import React, { useEffect, useRef, useState } from "react"; import BrowserOnly from "@docusaurus/BrowserOnly"; import Admonition from "@theme/Admonition"; @@ -61,7 +61,7 @@ export default function FeedbackForm({ enablePopup = false }) { setPopupEnabled(false); } }, - { threshold: 0.1 } + { threshold: 0.1 }, ); observer.observe(feedbackFormRef.current); @@ -232,7 +232,7 @@ const FloatingPopup = ({ onClose, onFeedbackSelect }) => { }; return ( -
+