-
Notifications
You must be signed in to change notification settings - Fork 6
Add Purview plugin #102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add Purview plugin #102
Changes from all commits
bfb135c
02b3388
2992e3c
3952610
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| { | ||
| "steps": [ | ||
| { | ||
| "displayName": "Authenticate and list collections", | ||
| "dataStream": { "name": "collections" }, | ||
| "required": true, | ||
| "error": "Could not authenticate or read collections. Check the account name, tenant/client ID, secret, and that the app registration has been added as Data Reader on the Purview root collection.", | ||
| "success": "Connected to Purview and read collections." | ||
| }, | ||
| { | ||
| "displayName": "List data sources", | ||
| "dataStream": { "name": "listDataSources" }, | ||
| "required": false, | ||
| "error": "Authenticated but could not list data sources. Add the app registration as Data Source Administrator on the Purview root collection.", | ||
| "success": "Data sources accessible." | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| [ | ||
| { | ||
| "name": "Purview Collection", | ||
| "sourceType": "Purview Collection", | ||
| "icon": "folder-tree", | ||
| "singular": "Collection", | ||
| "plural": "Collections" | ||
| }, | ||
| { | ||
| "name": "Purview Data Source", | ||
| "sourceType": "Purview Data Source", | ||
| "icon": "database", | ||
| "singular": "Data Source", | ||
| "plural": "Data Sources" | ||
| } | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| { | ||
| "name": "accountAssetCount", | ||
| "displayName": "Total Asset Count", | ||
| "description": "Total number of assets cataloged across the whole Purview account", | ||
| "tags": ["Assets"], | ||
| "baseDataSourceName": "httpRequestUnscoped", | ||
| "config": { | ||
| "httpMethod": "post", | ||
| "endpointPath": "datamap/api/search/query", | ||
| "getArgs": [ | ||
| { "key": "api-version", "value": "2023-09-01" } | ||
| ], | ||
| "postBody": { | ||
| "keywords": null, | ||
| "limit": 1 | ||
| }, | ||
| "postRequestScript": "accountAssetCount.js" | ||
| }, | ||
| "matches": "none", | ||
| "metadata": [ | ||
| { "name": "label", "displayName": "Label", "role": "label" }, | ||
| { "name": "totalAssets", "displayName": "Total Assets", "shape": "number", "role": "value" } | ||
| ], | ||
| "timeframes": false | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| { | ||
| "name": "assetCountByEntityType", | ||
| "displayName": "Asset Count by Entity Type", | ||
| "description": "Count of assets in the selected collection grouped by entity type", | ||
| "tags": ["Assets"], | ||
| "baseDataSourceName": "httpRequestScopedSingle", | ||
| "config": { | ||
| "httpMethod": "post", | ||
| "endpointPath": "datamap/api/search/query", | ||
| "getArgs": [ | ||
| { "key": "api-version", "value": "2023-09-01" } | ||
| ], | ||
| "postBody": { | ||
| "keywords": null, | ||
| "limit": 1, | ||
| "filter": { | ||
| "collectionId": "{{object.collectionName}}" | ||
| }, | ||
| "facets": [ | ||
| { | ||
| "facet": "entityType", | ||
| "count": 50, | ||
| "sort": { "count": "desc" } | ||
| } | ||
| ] | ||
| }, | ||
| "pathToData": "@search.facets.entityType", | ||
| "postRequestScript": "assetCountByEntityType.js" | ||
| }, | ||
| "matches": { "sourceType": { "type": "oneOf", "values": ["Purview Collection"] } }, | ||
| "metadata": [ | ||
| { "name": "entityType", "displayName": "Entity Type", "role": "label" }, | ||
| { "name": "count", "displayName": "Assets", "shape": "number" } | ||
| ], | ||
| "timeframes": false, | ||
| "defaultShaping": { "sort": { "by": [["count", "desc"]] } } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| { | ||
| "name": "assetLineage", | ||
| "displayName": "Asset Lineage", | ||
| "description": "Upstream and downstream lineage for an asset identified by its GUID", | ||
| "tags": ["Assets"], | ||
| "baseDataSourceName": "httpRequestUnscoped", | ||
| "ui": [ | ||
| { | ||
| "type": "text", | ||
| "name": "assetGuid", | ||
| "label": "Asset GUID", | ||
| "placeholder": "Asset GUID from the catalog", | ||
| "validation": { "required": true }, | ||
| "help": "The Purview asset's GUID. Copy it from the asset details page in the Purview portal, or from the **Asset GUID** column of the Search Assets stream." | ||
| }, | ||
| { | ||
| "type": "switch", | ||
| "name": "direction", | ||
| "label": "Direction", | ||
| "defaultValue": "BOTH", | ||
| "options": [ | ||
| { "value": "BOTH", "label": "Both" }, | ||
| { "value": "INPUT", "label": "Upstream" }, | ||
| { "value": "OUTPUT", "label": "Downstream" } | ||
| ] | ||
| }, | ||
| { | ||
| "type": "number", | ||
| "name": "depth", | ||
| "label": "Depth", | ||
| "defaultValue": 3, | ||
| "help": "Number of hops to traverse in each direction." | ||
|
Comment on lines
+28
to
+32
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== Locate assetLineage and nearby metadata =="
git ls-files | rg '(^|/)dataStreams/assetLineage\.json$|(^|/)metadata\.json$' | sed -n '1,80p'
echo
echo "== assetLineage relevant lines =="
sed -n '1,120p' plugins/MicrosoftPurview/v1/dataStreams/assetLineage.json || true
echo
echo "== Existing number constraints patterns in dataStreams =="
python3 - <<'PY'
import json, pathlib
for p in pathlib.Path('dataStreams').glob('*.json'):
try:
data=json.loads(p.read_text())
except Exception:
continue
if 'parameters' not in data:
continue
for pm in data.get('parameters', []):
if isinstance(pm, dict) and pm.get('type')=='number' and {'minimum','maximum','step','multipleOf','multipleOfInteger','min','max'}.intersection(pm.keys()):
print(p, json.dumps(pm, ensure_ascii=False, separators=(',',':'))[:300])
PY
echo
echo "== Search for Purview depth calls/docs references =="
rg -n "depth|lineage|assetLineage|minimum|multipleOf" plugins/MicrosoftPurview dataStreams -S || trueRepository: squaredup/plugins Length of output: 5455 🌐 Web query:
💡 Result: The Microsoft Purview Lineage "Get" REST API defines the depth parameter as an integer (int32) [1][2]. While the API documentation specifies the data type, it does not explicitly document a hard maximum integer value for the depth parameter beyond the constraints of a 32-bit signed integer [1][2]. In practical application, Microsoft Purview does not recommend using high depth values for extensive lineage traversal due to performance constraints [3]. For large or complex lineage graphs, it is recommended to use the paginated traversal endpoint (e.g., GET /datamap/api/atlas/v2/lineage/{guid}/next/) instead of attempting to retrieve the entire graph in a single request by increasing the depth parameter [3]. Increasing the depth to very high values can lead to request timeouts or performance degradation [3]. Citations:
Constrain
🤖 Prompt for AI Agents |
||
| } | ||
| ], | ||
| "config": { | ||
| "httpMethod": "get", | ||
| "endpointPath": "datamap/api/atlas/v2/lineage/{{assetGuid}}", | ||
| "getArgs": [ | ||
| { "key": "direction", "value": "{{direction}}" }, | ||
| { "key": "depth", "value": "{{depth}}" } | ||
| ], | ||
| "postRequestScript": "assetLineage.js" | ||
| }, | ||
| "manualConfigApply": true, | ||
| "matches": "none", | ||
| "metadata": [ | ||
| { "name": "guid", "displayName": "GUID", "shape": "guid", "visible": false }, | ||
| { "name": "name", "displayName": "Name", "role": "label" }, | ||
| { "name": "typeName", "displayName": "Entity Type" }, | ||
| { "name": "qualifiedName", "displayName": "Qualified Name" }, | ||
| { | ||
| "name": "role", | ||
| "displayName": "Role", | ||
| "shape": [ | ||
| "state", | ||
| { | ||
| "map": { | ||
| "success": ["Base"], | ||
| "warning": ["Upstream"], | ||
| "unknown": ["Downstream"] | ||
| } | ||
| } | ||
| ] | ||
| }, | ||
| { "name": "status", "displayName": "Status" }, | ||
| { | ||
| "name": "classifications", | ||
| "displayName": "Classifications" | ||
| } | ||
| ], | ||
| "timeframes": false | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| { | ||
| "name": "assetsByCollection", | ||
| "displayName": "Assets in Collection", | ||
| "description": "Assets found in the selected Purview collection", | ||
| "tags": ["Assets"], | ||
| "baseDataSourceName": "httpRequestScopedSingle", | ||
| "config": { | ||
| "httpMethod": "post", | ||
| "endpointPath": "datamap/api/search/query", | ||
| "getArgs": [ | ||
| { "key": "api-version", "value": "2023-09-01" } | ||
| ], | ||
| "postBody": { | ||
| "keywords": null, | ||
| "limit": 100, | ||
| "filter": { | ||
| "collectionId": "{{object.collectionName}}" | ||
| }, | ||
| "orderby": [{ "name": "ASC" }] | ||
| }, | ||
| "postRequestScript": "assetsByCollection.js", | ||
| "paging": { | ||
| "mode": "token", | ||
| "in": { "realm": "payload", "path": "continuationToken" }, | ||
| "out": { "realm": "body", "path": "continuationToken" } | ||
| } | ||
| }, | ||
| "matches": { "sourceType": { "type": "oneOf", "values": ["Purview Collection"] } }, | ||
| "metadata": [ | ||
| { "name": "id", "displayName": "Asset GUID", "shape": "guid", "visible": false }, | ||
| { "name": "name", "displayName": "Name", "role": "label" }, | ||
| { "name": "qualifiedName", "displayName": "Qualified Name" }, | ||
| { "name": "entityType", "displayName": "Entity Type" }, | ||
| { "name": "assetType", "displayName": "Asset Type" }, | ||
| { "name": "classification", "displayName": "Classifications" }, | ||
| { "name": "term", "displayName": "Glossary Terms" }, | ||
| { "name": "label", "displayName": "Labels" }, | ||
| { "name": "description", "displayName": "Description" }, | ||
| { "name": "owner", "displayName": "Owner" } | ||
| ], | ||
| "timeframes": false | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| { | ||
| "name": "assetsByEntityTypeGlobal", | ||
| "displayName": "Asset Count by Entity Type", | ||
| "description": "Count of assets grouped by entity type across the whole account", | ||
| "tags": ["Assets"], | ||
| "baseDataSourceName": "httpRequestUnscoped", | ||
| "config": { | ||
| "httpMethod": "post", | ||
| "endpointPath": "datamap/api/search/query", | ||
| "getArgs": [ | ||
| { "key": "api-version", "value": "2023-09-01" } | ||
| ], | ||
| "postBody": { | ||
| "keywords": null, | ||
| "limit": 1000 | ||
| }, | ||
| "postRequestScript": "assetsByEntityTypeGlobal.js" | ||
|
Comment on lines
+13
to
+17
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win Paginate both account-wide aggregations before counting. Both streams cap Purview search responses at 1,000 rows but omit continuation-token paging. Their scripts aggregate only
📍 Affects 2 files
🤖 Prompt for AI Agents |
||
| }, | ||
| "matches": "none", | ||
| "metadata": [ | ||
| { "name": "entityType", "displayName": "Entity Type", "role": "label" }, | ||
| { "name": "count", "displayName": "Assets", "shape": "number" } | ||
| ], | ||
| "timeframes": false, | ||
| "defaultShaping": { "sort": { "by": [["count", "desc"]] } } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| { | ||
| "name": "classificationCoverage", | ||
| "displayName": "Classification Coverage", | ||
| "description": "Count of assets carrying each classification across the whole account", | ||
| "tags": ["Classifications"], | ||
| "baseDataSourceName": "httpRequestUnscoped", | ||
| "config": { | ||
| "httpMethod": "post", | ||
| "endpointPath": "datamap/api/search/query", | ||
| "getArgs": [ | ||
| { "key": "api-version", "value": "2023-09-01" } | ||
| ], | ||
| "postBody": { | ||
| "keywords": null, | ||
| "limit": 1000 | ||
| }, | ||
| "postRequestScript": "classificationCoverage.js" | ||
| }, | ||
| "matches": "none", | ||
| "metadata": [ | ||
| { "name": "classification", "displayName": "Classification", "role": "label" }, | ||
| { "name": "assets", "displayName": "Assets", "shape": "number" }, | ||
| { | ||
| "name": "coverage", | ||
| "displayName": "% of Total Assets", | ||
| "shape": ["percent", { "asZeroToOne": true, "decimalPlaces": 1 }] | ||
| } | ||
| ], | ||
| "timeframes": false, | ||
| "defaultShaping": { "sort": { "by": [["assets", "desc"]] } } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,27 @@ | ||||||||||||||||||
| { | ||||||||||||||||||
| "name": "classificationTypes", | ||||||||||||||||||
| "displayName": "Classification Types", | ||||||||||||||||||
| "description": "All classification type definitions in the Purview account", | ||||||||||||||||||
| "tags": ["Classifications"], | ||||||||||||||||||
| "baseDataSourceName": "httpRequestUnscoped", | ||||||||||||||||||
| "config": { | ||||||||||||||||||
| "httpMethod": "get", | ||||||||||||||||||
| "endpointPath": "datamap/api/atlas/v2/types/typedefs", | ||||||||||||||||||
| "getArgs": [ | ||||||||||||||||||
| { "key": "type", "value": "classification" } | ||||||||||||||||||
| ], | ||||||||||||||||||
| "postRequestScript": "classificationTypes.js" | ||||||||||||||||||
|
Comment on lines
+10
to
+13
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg 'plugins/MicrosoftPurview/v1/dataStreams/(classificationTypes\.(json|js)|metadata\.json)|plugins/MicrosoftPurview/.*/metadata.json' || true
echo
echo "== classificationTypes.json =="
sed -n '1,220p' plugins/MicrosoftPurview/v1/dataStreams/classificationTypes.json
echo
echo "== classificationTypes.js =="
sed -n '1,260p' plugins/MicrosoftPurview/v1/dataStreams/classificationTypes.js
echo
echo "== metadata snippets =="
for f in plugins/MicrosoftPurview/v1/metadata.json plugins/MicrosoftPurview/metadata.json; do
if [ -f "$f" ]; then echo "--- $f"; sed -n '1,220p' "$f"; fi
done
echo
echo "== Purview type filter occurrences =="
rg -n '"type"|TypeCategory|classificationTypes|typeCategory|classifications|classification' plugins/MicrosoftPurview . --glob '!node_modules' --glob '!dist' --glob '!build' | head -200Repository: squaredup/plugins Length of output: 1568 🌐 Web query:
💡 Result: In the Microsoft Purview Data Map REST API (based on Apache Atlas), CLASSIFICATION is a valid value for the TypeCategory enum [1][2][3]. This enum is used to categorize type definitions (typedefs) within the metadata system [1][4][2]. When listing type definitions via the REST API—such as using the endpoint {endpoint}/datamap/api/atlas/v2/types/typedefs—you can use the type parameter to filter by these categories [1]. For example, by setting the query parameter type=CLASSIFICATION, you can retrieve only the classification type definitions [1][3]. The supported categories generally include: - PRIMITIVE - OBJECT_ID_TYPE - ENUM - STRUCT - CLASSIFICATION - ENTITY - RELATIONSHIP - BUSINESS_METADATA [1][2] If you are looking for specific assets that have been classified, you typically use different endpoints, such as retrieving classifications for a specific entity GUID [5] or using search/query APIs [6], as classification labels are properties of an entity rather than distinct assets themselves in the hierarchy [7][8]. Citations:
🌐 Web query:
💡 Result: In the SquaredUp plugins architecture, data streams are defined as independent JSON files located within a plugin's Citations:
Use the documented
Proposed fix "getArgs": [
- { "key": "type", "value": "classification" }
+ { "key": "type", "value": "CLASSIFICATION" }
],📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||
| }, | ||||||||||||||||||
| "matches": "none", | ||||||||||||||||||
| "metadata": [ | ||||||||||||||||||
| { "name": "name", "displayName": "Classification", "role": "label" }, | ||||||||||||||||||
| { "name": "description", "displayName": "Description" }, | ||||||||||||||||||
| { "name": "category", "displayName": "Category" }, | ||||||||||||||||||
| { "name": "typeVersion", "displayName": "Version" }, | ||||||||||||||||||
| { "name": "superTypes", "displayName": "Super Types" }, | ||||||||||||||||||
| { "name": "createdBy", "displayName": "Created By" }, | ||||||||||||||||||
| { "name": "createTime", "displayName": "Created", "shape": "date" }, | ||||||||||||||||||
| { "name": "guid", "displayName": "GUID", "shape": "guid", "visible": false } | ||||||||||||||||||
| ], | ||||||||||||||||||
| "timeframes": false | ||||||||||||||||||
| } | ||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| { | ||
| "name": "collectionClassificationSummary", | ||
| "displayName": "Classification Summary", | ||
| "description": "Classified vs unclassified asset counts for the selected collection", | ||
| "tags": ["Classifications"], | ||
| "baseDataSourceName": "httpRequestScopedSingle", | ||
| "config": { | ||
| "httpMethod": "post", | ||
| "endpointPath": "datamap/api/search/query", | ||
| "getArgs": [ | ||
| { "key": "api-version", "value": "2023-09-01" } | ||
| ], | ||
| "postBody": { | ||
| "keywords": null, | ||
| "limit": 1000, | ||
| "filter": { | ||
| "collectionId": "{{object.collectionName}}" | ||
| } | ||
| }, | ||
| "paging": { | ||
| "mode": "token", | ||
| "in": { "realm": "payload", "path": "continuationToken" }, | ||
| "out": { "realm": "body", "path": "continuationToken" } | ||
| }, | ||
| "postRequestScript": "collectionClassificationSummary.js" | ||
| }, | ||
| "matches": { "sourceType": { "type": "oneOf", "values": ["Purview Collection"] } }, | ||
| "metadata": [ | ||
| { "name": "state", "displayName": "State", "shape": ["state", { "map": { "success": ["Classified"], "warning": ["Unclassified"] } }] }, | ||
| { "name": "label", "displayName": "Category", "role": "label" }, | ||
| { "name": "assets", "displayName": "Assets", "shape": "number", "role": "value" } | ||
| ], | ||
| "timeframes": false | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| { | ||
| "name": "collectionClassifiedAssets", | ||
| "displayName": "Classified Assets", | ||
| "description": "Assets with classifications in the selected collection, one row per asset-classification pair", | ||
| "tags": ["Classifications"], | ||
| "baseDataSourceName": "httpRequestScopedSingle", | ||
| "config": { | ||
| "httpMethod": "post", | ||
| "endpointPath": "datamap/api/search/query", | ||
| "getArgs": [ | ||
| { "key": "api-version", "value": "2023-09-01" } | ||
| ], | ||
| "postBody": { | ||
| "keywords": null, | ||
| "limit": 1000, | ||
| "filter": { | ||
| "collectionId": "{{object.collectionName}}" | ||
| } | ||
| }, | ||
| "paging": { | ||
| "mode": "token", | ||
| "in": { "realm": "payload", "path": "continuationToken" }, | ||
| "out": { "realm": "body", "path": "continuationToken" } | ||
| }, | ||
| "postRequestScript": "collectionClassifiedAssets.js" | ||
| }, | ||
| "matches": { "sourceType": { "type": "oneOf", "values": ["Purview Collection"] } }, | ||
| "metadata": [ | ||
| { "name": "assetName", "displayName": "Asset", "role": "label" }, | ||
| { "name": "entityType", "displayName": "Entity Type" }, | ||
| { "name": "collectionId", "displayName": "Collection", "visible": false }, | ||
| { "name": "classification", "displayName": "Classification" } | ||
| ], | ||
| "timeframes": false | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: squaredup/plugins
Length of output: 6232
🌐 Web query:
Microsoft Purview Data Map lineage REST API get lineage assetGuid asset guid path💡 Result:
To retrieve lineage information for a specific asset in the Microsoft Purview Data Map via the REST API, you primarily use the lineage endpoint identified by the asset's GUID [1][2]. The API endpoint to get lineage by asset GUID is: GET {endpoint}/datamap/api/atlas/v2/lineage/{guid}?direction={direction}&depth={depth} [2] Key parameters for this request include: - {endpoint}: The base URL for your Purview Data Map data plane [2]. - {guid}: The globally unique identifier (GUID) of the asset for which you want to retrieve lineage [2]. - direction: Required query parameter specifying the lineage flow (INPUT, OUTPUT, or BOTH) [2]. - depth: Optional query parameter defining the number of hops (levels) in the lineage graph to retrieve [2]. If you do not have the asset GUID but possess unique attributes (such as a qualifiedName), you can use the Get By Unique Attribute endpoint: GET {endpoint}/datamap/api/atlas/v2/lineage/uniqueAttribute/type/{typeName}?attr:{attrName}={value}&direction={direction}&depth={depth} [3] For scenarios involving large lineage graphs or the need to traverse beyond the initial depth, the API supports pagination via the lineage next page endpoint: GET {endpoint}/datamap/api/atlas/v2/lineage/{guid}/next/ [4] Note that Microsoft Purview lineage is built upon the Apache Atlas API structure [3][5]. Lineage data returned by these endpoints includes a mapping of GUIDs to entity details (guidEntityMap) and a list of relations (relations) that define the connection between assets [3][2]. If you are performing tasks such as refreshing lineage, it is often more efficient to identify and manipulate the Process entities associated with the lineage rather than individual relationship records [4].
Citations:
🏁 Script executed:
Repository: squaredup/plugins
Length of output: 5133
🏁 Script executed:
Repository: squaredup/plugins
Length of output: 5853
🏁 Script executed:
Repository: squaredup/plugins
Length of output: 358
🏁 Script executed:
Repository: squaredup/plugins
Length of output: 50373
🌐 Web query:
Azure Data Explorer Kusto Azure Monitor query parameter encoded in URL slash allowed documentation💡 Result:
When passing parameters in URLs for Azure Data Explorer (ADX) or Azure Monitor (such as in deep links or API requests), standard percent-encoding (HTML URI encoding) rules apply [1][2]. Regarding the use of forward slashes (/), they are reserved characters in URLs. If a forward slash is part of the data being passed (and not intended as a URL path delimiter), it must be percent-encoded as %2F to ensure the URL is interpreted correctly by the receiving service [3][4][5][6]. For Kusto (ADX) UI deep links specifically, the query parameter must be encoded according to standard URI query string rules [1][2]. If you are passing a Kusto query, the official documentation recommends: 1. Standard HTTP query parameter encoding [1][2]. 2. Alternatively, for complex or long queries, using a gzip-compressed and then Base64-encoded string to avoid URI length limitations and character encoding issues [1][2][7][8]. If you are dealing with resource IDs or other path-like parameters in Azure portal URLs (such as those for Azure Monitor Workbooks or Log Analytics), these often require forward slashes to be encoded as %2F to prevent the portal from misinterpreting the URL structure [4][5]. In Kusto Query Language (KQL) itself, if you need to generate these encoded strings programmatically, you can use built-in functions such as url_encode or url_encode_component [3][6]. Note that url_encode follows application/x-www-form-urlencoded rules (encoding spaces as '+'), while url_encode_component encodes spaces as '%20' [3][6].
Citations:
🌐 Web query:
Python urllib.parse quote slash / encoded / encoded %2F default safe💡 Result:
In Python's urllib.parse.quote function, the slash character ('/') is included in the default set of safe characters [1][2]. Because the 'safe' parameter defaults to '/' [1][2], the quote function will not encode slashes by default [1][3]. This behavior is designed to allow developers to quote URL paths while preserving the directory structure [3]. If you wish to encode slashes as '%2F', you must explicitly set the 'safe' parameter to an empty string (or any string that does not include '/') when calling the function [1][4]: urllib.parse.quote('a/b', safe='') # Result: 'a%2Fb' In contrast, the related function urllib.parse.quote_plus has a default 'safe' value of an empty string ('') [1][2]. Consequently, quote_plus will encode slashes as '%2F' by default [1][4].
Citations:
Validate
assetGuidbefore interpolating it into the path.assetGuidaccepts path characters (/,?,#) while Line 37 inserts the raw value intodatamap/api/atlas/v2/lineage/{{assetGuid}}. Since the API expects a single GUID path segment, validate against an appropriate GUID format before interpolation.🤖 Prompt for AI Agents