Skip to content

Add Purview plugin#102

Draft
johnhayes-squaredup wants to merge 4 commits into
squaredup:mainfrom
johnhayes-squaredup:add-purview-plugin
Draft

Add Purview plugin#102
johnhayes-squaredup wants to merge 4 commits into
squaredup:mainfrom
johnhayes-squaredup:add-purview-plugin

Conversation

@johnhayes-squaredup

@johnhayes-squaredup johnhayes-squaredup commented Jul 23, 2026

Copy link
Copy Markdown

🔌 Plugin overview

  • Plugin name: Microsoft Purview
  • Purpose / problem solved: Provides users with an overview of key metrics and processes in their Purview domain. This will provide value to customers managing their data governance activities.
  • Primary audience (e.g. platform teams, SREs, product teams): Data analysts, data architects, DBAs, senior managers.
  • Authentication method(s) (e.g. OAuth, Username/Password, API Key): Microsoft OAuth (via an Azure App Registration credential)

🖼️ Plugin screenshots

purview-scans
classifications-and-terms

Plugin configuration

create-connection

Default dashboards

overview-dashboard

🧪 Testing

I have carried out functional testing to ensure that:

  • the data source can connect to the Purview instance
  • all data streams are working as expected
  • all expected data is being shown in the UI

⚠️ Known limitations

This is a first iteration of the plugin and I have encountered some data hierarchy issues which mean that data joins do not work as elegantly as I would like. For example, it is not possible to see all Scans at once - they can only be viewed per data source.

For the purpose of this exercise I have created a free Purview instance. This means that I do not have access to Enterprise features so these are not included in the data source

Some Purview functionality is in preview mode only and is not yet supported by the API

I have only been able to test against a small dataset. I don't now how the data source will perform under large loads

In a future iteration I would like to:

  • include coverage of data policies
  • have more flexible coverage of scans
  • go into more depth on Governance Domains

📚 Checklist

  • Plugin, datastream and UI naming follow SquaredUp guidelines
  • Logo added
  • One or more dashboards added
  • README added including configuration guidance
  • No secrets or credentials included
  • I agree to the Code of Conduct

Summary by CodeRabbit

  • New Features
    • Added Microsoft Purview integration with collections, data sources, scans, governance domains, glossary terms, policies, classifications, assets, and lineage.
    • Added asset search with keyword, entity type, and classification filters.
    • Added collection analytics, classification coverage, asset counts, and scan history.
    • Added an Overview dashboard with metrics, charts, and tables.
    • Added custom object types, scopes, configuration validation, and OAuth setup fields.
  • Documentation
    • Added setup requirements, supported data streams, permissions, and known limitations.

johnhayes-squaredup and others added 4 commits July 20, 2026 16:44
- Add dataSourceName field to Scans on Data Source stream, read directly
  from the API response rather than parsed from the scan id
- Fix lastRunResult fields in dataSourceScans and scansForDataSource:
  status was scanRunStatus, times were nested under
  discoveryExecutionDetails, and runType was scanLevelType — all
  previously broken due to incorrect field name assumptions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix classification summary (count from assets instead of missing facet count field)
- Add Classified Assets stream (all classifications, one row per asset-classification pair)
- Add Assets with Custom Classifications stream (non-Microsoft classifications only)
- Add Custom Classifications stream (account-wide, available on Collection and Data Source)
- Update Scans on Data Source stream with dataSourceName field and postRequestScript
- Add Duration (s) numeric column to Scan History for average queries
- Restrict Scan History to single object selection
- Remove Collection and Data Source out-of-the-box dashboards

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resize Classification Coverage and Metadata Policies tiles to 2x2 and
stack them on the right side of the Asset Count by Entity Type tile.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Governance Domains stream (Unified Catalog API, account-wide)
- Add Glossary Terms stream scoped to Purview Governance Domain objects
- Index Governance Domains as a new object type
- Strip HTML from description fields in both streams
- Update README with Unified Catalog permission requirements
- Add Purview Governance Domain to objectTypes and What gets indexed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The Microsoft Purview v1 plugin is added with OAuth configuration, validation, indexed collections, data sources, and governance domains. It also adds on-demand asset, lineage, classification, policy, glossary, and scan streams, normalized response scripts, an Overview dashboard, scopes, and documentation.

Changes

Microsoft Purview plugin foundation

Layer / File(s) Summary
Plugin foundation and indexing contracts
plugins/MicrosoftPurview/v1/metadata.json, ui.json, custom_types.json, configValidation.json, indexDefinitions/default.json, docs/README.md
Defines OAuth metadata, required configuration fields, Purview object types, validation steps, indexed object mappings, prerequisites, and supported data streams.

Indexed entities and operational streams

Layer / File(s) Summary
Indexed entities and operational streams
plugins/MicrosoftPurview/v1/dataStreams/{collections,listDataSources,governanceDomains,...}.json, dataStreams/scripts/*
Adds collection, data source, governance domain, classification, glossary, policy, and scan streams with pagination, metadata schemas, and response normalization scripts.

On-demand asset analytics

Layer / File(s) Summary
On-demand asset analytics
plugins/MicrosoftPurview/v1/dataStreams/{searchAssets,assetsByCollection,assetLineage,...}.json, dataStreams/scripts/*
Adds asset search, collection asset listings, entity-type counts, classification coverage, classified asset views, lineage, and policy coverage transformations.

Dashboard and scope wiring

Layer / File(s) Summary
Dashboard and scope wiring
plugins/MicrosoftPurview/v1/defaultContent/*
Registers an Overview dashboard, configures collection and data source scopes, and binds scalar, chart, and table tiles to Purview streams.

Sequence Diagram(s)

sequenceDiagram
  participant PluginConfiguration
  participant ConfigValidation
  participant PurviewAPI
  participant IndexDefinition
  participant Dashboard
  PluginConfiguration->>ConfigValidation: validate configured credentials
  ConfigValidation->>PurviewAPI: request collections and data sources
  PurviewAPI-->>ConfigValidation: return validation results
  IndexDefinition->>PurviewAPI: retrieve indexed Purview entities
  PurviewAPI-->>IndexDefinition: return collections, data sources, and domains
  Dashboard->>PurviewAPI: request on-demand asset analytics
  PurviewAPI-->>Dashboard: return transformed stream data
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding the Purview plugin.
Description check ✅ Passed The description follows the new-plugin template well and includes overview, screenshots, testing, limitations, and checklist items.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/MicrosoftPurview/v1/dataStreams/assetLineage.json`:
- Around line 28-32: Constrain the depth field in the asset lineage
configuration to valid Purview lineage hop counts: require numeric integer
input, enforce a minimum of 0, and add an appropriate maximum if supported by
the API. Keep the existing defaultValue of 3 and help text unchanged.
- Around line 7-14: Update the assetGuid field validation in the UI
configuration to require a valid GUID format before the value is used in the
lineage endpoint path. Keep the field required and ensure values containing path
characters such as /, ?, or # are rejected.

In `@plugins/MicrosoftPurview/v1/dataStreams/assetsByEntityTypeGlobal.json`:
- Around line 13-17: Configure token-based pagination in the postRequest
configuration for assetsByEntityTypeGlobal.json (lines 13-17) and
classificationCoverage.json (lines 13-17), matching the contract used by
assetsByCollection.json. Ensure all Purview response pages are combined before
assetsByEntityTypeGlobal.js and classificationCoverage.js aggregate and count
results.

In `@plugins/MicrosoftPurview/v1/dataStreams/classificationTypes.json`:
- Around line 10-13: Update the getArgs entry in classificationTypes.json to use
the documented uppercase CLASSIFICATION value for the type filter, while leaving
the classificationTypes.js postRequestScript unchanged.

In `@plugins/MicrosoftPurview/v1/dataStreams/collections.json`:
- Around line 28-68: Replace the mustache-style valueExpression transformations
in plugins/MicrosoftPurview/v1/dataStreams/collections.json lines 28-68 with map
transformations for collectionName, displayName, parentCollectionName, and
sourceType, preserving alias, fallback, nested-field, and constant-value
behavior. Apply the same conversion in
plugins/MicrosoftPurview/v1/dataStreams/listDataSources.json lines 24-78 for the
nested collection, resource group, subscription, portal URL, and sourceType
fields; both sites require direct changes.

In `@plugins/MicrosoftPurview/v1/dataStreams/dataSourceScans.json`:
- Around line 29-34: Update the normalization script in dataSourceScans.js to
emit collection from props.collection?.referenceName, then change the collection
entry in dataSourceScans.json to a normal metadata field without computed or
valueExpression properties. Remove the dotted implementation-field derivation
and preserve the existing display name.

In `@plugins/MicrosoftPurview/v1/dataStreams/scansForDataSource.json`:
- Around line 2-6: Add the mandatory tags property to the scansForDataSource
stream definition, reusing the existing Data Sources tag used by scanHistory.
Keep the current metadata and hidden visibility unchanged.

In `@plugins/MicrosoftPurview/v1/dataStreams/scripts/accountAssetCount.js`:
- Around line 1-2: Update the asset-count result construction around
`@search.count` to detect `data?.['`@search.count.approximate`'] === true` and
avoid presenting the estimated value as the exact “Total Assets” KPI, using an
appropriate status field/label or equivalent non-exact representation. Increment
the plugin `version` in `metadata.json` for this change.

In `@plugins/MicrosoftPurview/v1/dataStreams/scripts/assetLineage.js`:
- Around line 7-16: Update the lineage processing around the relations loop and
role assignment to traverse the graph from baseGuid, collecting every reachable
upstream and downstream node across multiple hops rather than only direct
neighbors. Preserve Base for baseGuid and assign roles from the complete
traversal sets, then increment the version in metadata.json to reflect the
behavior change.

In `@plugins/MicrosoftPurview/v1/dataStreams/scripts/customClassifications.js`:
- Around line 3-12: The custom-classification output must expose category and
typeVersion. In
plugins/MicrosoftPurview/v1/dataStreams/scripts/customClassifications.js lines
3-12, update the normalized rows produced by the defs filter/map to include both
fields; in plugins/MicrosoftPurview/v1/dataStreams/customClassifications.json
lines 16-22, declare metadata for those same fields so Category and Version are
available to consumers.

In `@plugins/MicrosoftPurview/v1/dataStreams/searchAssets.json`:
- Around line 9-13: Update the keywords text field in searchAssets.json so its
placeholder includes an example search keyword, while retaining that the field
is optional.
- Around line 39-42: Update the postBody limit expression in the Purview search
request to coerce the input, constrain it to the valid 1–1000 range, and forward
at most 1000 while preserving the existing default behavior. Also constrain the
associated UI number field, if present in the diff, with minimum 1 and maximum
1000.

In `@plugins/MicrosoftPurview/v1/indexDefinitions/default.json`:
- Around line 2-50: Implement scan indexing by adding a scan-stream import step
with a stable ID, scan label, and “Purview Scan” source type in
plugins/MicrosoftPurview/v1/indexDefinitions/default.json lines 2-50; add
“Purview Scan” to objectTypes in plugins/MicrosoftPurview/v1/metadata.json lines
24-28, and retain the corresponding scan-indexing and object-type documentation
in plugins/MicrosoftPurview/v1/docs/README.md lines 7-7 and 63-70.

In `@plugins/MicrosoftPurview/v1/metadata.json`:
- Around line 45-52: The Microsoft Purview metadata configuration currently
routes all streams through the account-scoped baseUrl. Add a separate
authenticated base configuration for https://api.purview-service.microsoft.com/
using the existing OAuth2 settings, then update the governanceDomains and
glossaryTerms stream definitions to reference that base while leaving other
streams on the account-scoped endpoint.

In `@plugins/MicrosoftPurview/v1/ui.json`:
- Around line 12-37: Update the tenantId, clientId, and clientSecret fields in
the UI configuration with example GUID-based placeholders for the IDs and
concise help text describing where to obtain each credential. Preserve the
existing labels, field types, and required validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 97e34756-0fb3-4a75-a5c5-73ed08e038f5

📥 Commits

Reviewing files that changed from the base of the PR and between 2c93cd8 and 3952610.

⛔ Files ignored due to path filters (1)
  • plugins/MicrosoftPurview/v1/icon.svg is excluded by !**/*.svg
📒 Files selected for processing (47)
  • plugins/MicrosoftPurview/v1/configValidation.json
  • plugins/MicrosoftPurview/v1/custom_types.json
  • plugins/MicrosoftPurview/v1/dataStreams/accountAssetCount.json
  • plugins/MicrosoftPurview/v1/dataStreams/assetCountByEntityType.json
  • plugins/MicrosoftPurview/v1/dataStreams/assetLineage.json
  • plugins/MicrosoftPurview/v1/dataStreams/assetsByCollection.json
  • plugins/MicrosoftPurview/v1/dataStreams/assetsByEntityTypeGlobal.json
  • plugins/MicrosoftPurview/v1/dataStreams/classificationCoverage.json
  • plugins/MicrosoftPurview/v1/dataStreams/classificationTypes.json
  • plugins/MicrosoftPurview/v1/dataStreams/collectionClassificationSummary.json
  • plugins/MicrosoftPurview/v1/dataStreams/collectionClassifiedAssets.json
  • plugins/MicrosoftPurview/v1/dataStreams/collectionCustomClassifiedAssets.json
  • plugins/MicrosoftPurview/v1/dataStreams/collectionPolicyCoverage.json
  • plugins/MicrosoftPurview/v1/dataStreams/collections.json
  • plugins/MicrosoftPurview/v1/dataStreams/customClassifications.json
  • plugins/MicrosoftPurview/v1/dataStreams/dataSourceScans.json
  • plugins/MicrosoftPurview/v1/dataStreams/glossaryTerms.json
  • plugins/MicrosoftPurview/v1/dataStreams/governanceDomains.json
  • plugins/MicrosoftPurview/v1/dataStreams/listDataSources.json
  • plugins/MicrosoftPurview/v1/dataStreams/metadataPolicies.json
  • plugins/MicrosoftPurview/v1/dataStreams/scanHistory.json
  • plugins/MicrosoftPurview/v1/dataStreams/scansForDataSource.json
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/accountAssetCount.js
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/assetCountByEntityType.js
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/assetLineage.js
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/assetsByCollection.js
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/assetsByEntityTypeGlobal.js
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/classificationCoverage.js
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/classificationTypes.js
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/collectionClassificationSummary.js
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/collectionClassifiedAssets.js
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/collectionCustomClassifiedAssets.js
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/collectionPolicyCoverage.js
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/customClassifications.js
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/dataSourceScans.js
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/glossaryTerms.js
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/governanceDomains.js
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/metadataPolicies.js
  • plugins/MicrosoftPurview/v1/dataStreams/scripts/searchAssets.js
  • plugins/MicrosoftPurview/v1/dataStreams/searchAssets.json
  • plugins/MicrosoftPurview/v1/defaultContent/manifest.json
  • plugins/MicrosoftPurview/v1/defaultContent/overview.dash.json
  • plugins/MicrosoftPurview/v1/defaultContent/scopes.json
  • plugins/MicrosoftPurview/v1/docs/README.md
  • plugins/MicrosoftPurview/v1/indexDefinitions/default.json
  • plugins/MicrosoftPurview/v1/metadata.json
  • plugins/MicrosoftPurview/v1/ui.json

Comment on lines +7 to +14
"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."

Copy link
Copy Markdown
Contributor

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:

#!/bin/bash
set -euo pipefail

echo "Files matching assetLineage.json:"
fd -a 'assetLineage\.json$' . | sed 's#^\./##'

file="$(fd 'assetLineage\.json$' . | grep 'plugins/MicrosoftPurview/v1/dataStreams/assetLineage.json' || true)"
if [ -n "$file" ]; then
  echo
  echo "assetLineage.json content:"
  cat -n "$file"
fi

echo
echo "Search for plugin renderer/path interpolation and assetGuid usages:"
rg -n '"assetGuid"|endpointPath|getLineage|assetLineage|assetGuid' plugins/MicrosoftPurview -S

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:

#!/bin/bash
set -euo pipefail

echo "Find plugin package metadata and related MicrosoftPurview dataStreams:"
fd -a . plugins/MicrosoftPurview/v1 | sed 's#^\./##'

echo
echo "MicrosoftPurview package files and relevant stream configs:"
for f in $(fd '{metadata\.json|package\.json|plugin\.json|settings.*\.json}$' plugins/MicrosoftPurview/v1); do
  echo "--- $f"
  wc -l "$f"
done

echo
echo "Search for endpointPath substitution implementation:"
rg -n "endpointPath|{{.*}}|url\\.|URL|encodeURIComponent|encodeURI|replace\\(" -S --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' . | head -n 200

Repository: squaredup/plugins

Length of output: 5133


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "MicrosoftPurview plugin metadata and relevant files:"
cat -n plugins/MicrosoftPurview/v1/metadata.json

echo
echo "Other endpointPath examples:"
rg -n '"endpointPath"' plugins/MicrosoftPurview/v1/dataStreams -S

echo
echo "Global search for endpointPath template substitution:"
rg -n 'endpointPath|{{[A-Za-z0-9_.]+}}|encodeURIComponent|encodeURI' -S --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' . | head -n 200

echo
echo "HTTP request integration references:"
rg -n 'httpRequest|baseDataSourceName|endpointPath|dataStreams|render|request' -S --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' . | head -n 300

Repository: squaredup/plugins

Length of output: 5853


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Global search for endpointPath template substitution:"
rg -n 'endpointPath|{{[A-Za-z0-9_.]*}}|encodeURIComponent|encodeURI' -S --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' . | head -n 300

echo
echo "HTTP request integration references:"
rg -n 'httpRequest|baseDataSource|endpointPath|dataStreams|renders?|request' -S --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' . | head -n 500

Repository: squaredup/plugins

Length of output: 358


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Global search for endpointPath template substitution:"
rg -n 'endpointPath|{{[A-Za-z0-9_.]*}}|encodeURIComponent|encodeURI' -S . | head -n 300 || true

echo
echo "HTTP request integration references:"
rg -n 'httpRequest|baseDataSource|endpointPath|dataStreams|renders?|request' -S . | head -n 500 || true

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 assetGuid before interpolating it into the path.

assetGuid accepts path characters (/, ?, #) while Line 37 inserts the raw value into datamap/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
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/MicrosoftPurview/v1/dataStreams/assetLineage.json` around lines 7 -
14, Update the assetGuid field validation in the UI configuration to require a
valid GUID format before the value is used in the lineage endpoint path. Keep
the field required and ensure values containing path characters such as /, ?, or
# are rejected.

Comment on lines +28 to +32
"type": "number",
"name": "depth",
"label": "Depth",
"defaultValue": 3,
"help": "Number of hops to traverse in each direction."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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 || true

Repository: squaredup/plugins

Length of output: 5455


🌐 Web query:

Microsoft Purview lineage graph depth parameter maximum integer Get lineage REST API

💡 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 depth to the values supported by the Purview lineage API.

depth is passed directly to the lineage endpoint and Purview treats it as an int32; a bare number UI field can accept fractions, negatives, or non-numeric strings that do not represent a valid lineage hop count. Add integer/minimum constraints (for example, minimum: 0) and, if useful, an upper bound on hops.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/MicrosoftPurview/v1/dataStreams/assetLineage.json` around lines 28 -
32, Constrain the depth field in the asset lineage configuration to valid
Purview lineage hop counts: require numeric integer input, enforce a minimum of
0, and add an appropriate maximum if supported by the API. Keep the existing
defaultValue of 3 and help text unchanged.

Comment on lines +13 to +17
"postBody": {
"keywords": null,
"limit": 1000
},
"postRequestScript": "assetsByEntityTypeGlobal.js"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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 data.value, so larger accounts silently return incomplete entity-type counts and classification coverage. assetsByCollection.json demonstrates the required token-paging contract.

  • plugins/MicrosoftPurview/v1/dataStreams/assetsByEntityTypeGlobal.json#L13-L17: add token paging so all pages are included before assetsByEntityTypeGlobal.js aggregates counts.
  • plugins/MicrosoftPurview/v1/dataStreams/classificationCoverage.json#L13-L17: add the same token paging so classificationCoverage.js computes coverage from the complete result set.
📍 Affects 2 files
  • plugins/MicrosoftPurview/v1/dataStreams/assetsByEntityTypeGlobal.json#L13-L17 (this comment)
  • plugins/MicrosoftPurview/v1/dataStreams/classificationCoverage.json#L13-L17
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/MicrosoftPurview/v1/dataStreams/assetsByEntityTypeGlobal.json` around
lines 13 - 17, Configure token-based pagination in the postRequest configuration
for assetsByEntityTypeGlobal.json (lines 13-17) and classificationCoverage.json
(lines 13-17), matching the contract used by assetsByCollection.json. Ensure all
Purview response pages are combined before assetsByEntityTypeGlobal.js and
classificationCoverage.js aggregate and count results.

Comment on lines +10 to +13
"getArgs": [
{ "key": "type", "value": "classification" }
],
"postRequestScript": "classificationTypes.js"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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 -200

Repository: squaredup/plugins

Length of output: 1568


🌐 Web query:

Microsoft Purview REST API list TypeCategory enum value CLASSIFICATION type query parameter

💡 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:

github squaredup plugins MicrosoftPurview v1 dataStreams classificationTypes.js

💡 Result:

In the SquaredUp plugins architecture, data streams are defined as independent JSON files located within a plugin's dataStreams directory [1]. Based on the official squaredup/plugins repository structure, a plugin version is organized as follows: plugins/<plugin-name>/v1/dataStreams/ [2][1]. There is no standard or required file named classificationTypes.js within the dataStreams folder or the broader plugin structure [2][1]. SquaredUp plugin data streams typically consist of a .json file defining the stream's configuration and, optionally, a script file (often named handler.js or similar) [2][1]. If you are encountering a reference to classificationTypes.js in a Microsoft Purview-related plugin or context, it is likely either: 1. A custom, non-standard component specific to a particular community-authored plugin implementation [3]. 2. A misunderstanding of the SquaredUp plugin structure, where standard files are metadata.json, ui.json, custom_types.json, and data_streams.json [2]. You can verify the contents of any specific plugin by exploring the squaredup/plugins repository on GitHub [3][4]. The repository documentation and the SKILL.md file provide the authoritative guidance for plugin development and structure [1].

Citations:


Use the documented CLASSIFICATION filter value.

getArgs sends type=classification, but Microsoft Purview’s TypeCategory filter for this typedefs endpoint uses CLASSIFICATION. Use the documented enum value so the stream is sent the requested classification-type filter.

Proposed fix
         "getArgs": [
-            { "key": "type", "value": "classification" }
+            { "key": "type", "value": "CLASSIFICATION" }
         ],
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"getArgs": [
{ "key": "type", "value": "classification" }
],
"postRequestScript": "classificationTypes.js"
"getArgs": [
{ "key": "type", "value": "CLASSIFICATION" }
],
"postRequestScript": "classificationTypes.js"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/MicrosoftPurview/v1/dataStreams/classificationTypes.json` around
lines 10 - 13, Update the getArgs entry in classificationTypes.json to use the
documented uppercase CLASSIFICATION value for the type filter, while leaving the
classificationTypes.js postRequestScript unchanged.

Comment on lines +28 to +68
"name": "collectionName",
"displayName": "Collection",
"computed": true,
"valueExpression": "{{ $['name'] }}",
"visible": false
},
{
"name": "friendlyName",
"displayName": "Friendly Name",
"visible": false
},
{
"name": "displayName",
"displayName": "Name",
"computed": true,
"valueExpression": "{{ $['friendlyName'] || $['name'] }}",
"role": "label"
},
{
"name": "description",
"displayName": "Description"
},
{
"name": "parentCollection",
"visible": false
},
{
"name": "parentCollectionName",
"computed": true,
"valueExpression": "{{ $['parentCollection'] && $['parentCollection'].referenceName ? $['parentCollection'].referenceName : '' }}",
"displayName": "Parent Collection"
},
{
"name": "collectionProvisioningState",
"displayName": "State"
},
{
"name": "sourceType",
"computed": true,
"valueExpression": "Purview Collection",
"visible": false

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use map for the repeated field transformations.

Both streams use mustache-style valueExpression transformations for aliases, fallbacks, and nested-field extraction. Replace these with map transformations to follow the data-stream guideline.

  • plugins/MicrosoftPurview/v1/dataStreams/collections.json#L28-L68: map collection aliases, parent name, display name, and source type.
  • plugins/MicrosoftPurview/v1/dataStreams/listDataSources.json#L24-L78: map nested collection, resource group, subscription, portal URL, and source type fields.
📍 Affects 2 files
  • plugins/MicrosoftPurview/v1/dataStreams/collections.json#L28-L68 (this comment)
  • plugins/MicrosoftPurview/v1/dataStreams/listDataSources.json#L24-L78
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/MicrosoftPurview/v1/dataStreams/collections.json` around lines 28 -
68, Replace the mustache-style valueExpression transformations in
plugins/MicrosoftPurview/v1/dataStreams/collections.json lines 28-68 with map
transformations for collectionName, displayName, parentCollectionName, and
sourceType, preserving alias, fallback, nested-field, and constant-value
behavior. Apply the same conversion in
plugins/MicrosoftPurview/v1/dataStreams/listDataSources.json lines 24-78 for the
nested collection, resource group, subscription, portal URL, and sourceType
fields; both sites require direct changes.

Source: Coding guidelines

Comment on lines +9 to +13
"type": "text",
"name": "keywords",
"label": "Keywords",
"placeholder": "Search keywords (optional)"
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use an example keyword placeholder.

The text-field placeholder describes the field but does not provide the required example.

Proposed fix
-            "placeholder": "Search keywords (optional)"
+            "placeholder": "e.g. customer"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"type": "text",
"name": "keywords",
"label": "Keywords",
"placeholder": "Search keywords (optional)"
},
"type": "text",
"name": "keywords",
"label": "Keywords",
"placeholder": "e.g. customer"
},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/MicrosoftPurview/v1/dataStreams/searchAssets.json` around lines 9 -
13, Update the keywords text field in searchAssets.json so its placeholder
includes an example search keyword, while retaining that the field is optional.

Source: Coding guidelines

Comment on lines +39 to +42
"postBody": {
"keywords": "{{ keywords || null }}",
"limit": "{{ Number(limit) || 100 }}",
"filter": "{{ (entityType || classification) ? { and: [entityType ? { entityType: entityType } : null, classification ? { classification: classification } : null].filter(Boolean) } : null }}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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 "## Candidate file"
fd -a 'searchAssets\.json$' . | sed 's#^\./##'

echo
echo "## data stream relevant contents"
file="$(fd 'searchAssets\.json$' . | head -n1)"
if [ -n "${file:-}" ]; then
  nl -ba "$file" | sed -n '1,140p'
fi

echo
echo "## metadata version references"
fd 'metadata\.json$' plugins | sed -n '1,50p' | while read -r f; do
  echo "--- $f"
  python3 - <<'PY' "$f"
import json,sys
p=sys.argv[1]
try:
    data=json.load(open(p))
except Exception as e:
    print(e); raise SystemExit
print({"path":p, "version": data.get("version"), "displayName": data.get("displayName")})
PY
done

echo
echo "## Limit-related occurrences in Purview plugin/data streams"
rg -n 'limit|query|queryAssets|queryAssetsWith|search/assets|search/assets' plugins/MicrosoftPurview || true

echo
echo "## Read-only behavioral probe of current template expression vs proposed expression"
python3 - <<'PY'
def current(limit):
    return int(limit) or 100
def proposed(limit):
    return min(1000, max(1, int(float(limit) if limit != '' else 100.0)))
samples = [None, '', -1, 0, 0.9, 1.2, 100, 999, 1000, 1001, 2000, float('inf')]
for s in samples:
    try:
        print(f"limit={s!r:15} current={current(s)!r:10} proposed={proposed(s)!r:10}")
    except Exception as e:
        print(f"limit={s!r:15} exception={type(e).__name__}: {e}")
PY

Repository: squaredup/plugins

Length of output: 325


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="/home/jailuser/git/plugins/MicrosoftPurview/v1/dataStreams/searchAssets.json"

echo "## Target file lines 1-140"
awk '{printf "%6d\t%s\n", NR, $0}' "$file" | sed -n '1,140p'

echo
echo "## Plugin metadata version"
python3 - <<'PY'
import json
from pathlib import Path
root = Path("/home/jailuser/git/plugins/MicrosoftPurview/v1")
for p in sorted(root.rglob("metadata.json")):
    try:
        data=json.loads(p.read_text())
    except Exception as e:
        print(f"{p}: read/error {e}")
        continue
    print(f"{p}: version={data.get('version')!r} displayName={data.get('displayName')!r}")
PY

echo
echo "## Limit-related occurrences in Purview plugin/data streams"
grep -RInE 'limit|queryAssets|queryAssetsWith|search/assets|assets/query?|postBody' /home/jailuser/git/plugins/MicrosoftPurview || true

echo
echo "## Read-only behavioral probe of current template expression vs proposed expression"
python3 - <<'PY'
import json

def current_value(limit):
    return int(limit) or 100

def proposed_value(limit):
    return min(1000, max(1, int(abs(float(limit)) if limit != '' else 100.0)))

samples = [None, "", -1, 0, 0.9, 1.2, 100, 999, 1000, 1001, 2000, -2000, float("inf")]
print("limit" + "".join(f"\t{m!r:>14}" for m in ("current", "proposed")))
for s in samples:
    try:
        print("current" + "".join(f"\t{current_value(s)!r:>14}" for m in ("current",)))
        print("proposed" + "".join(f"\t{proposed_value(s)!r:>14}" for m in ("proposed",)))
    except Exception as e:
        print(f"limit={s!r:12} exception={type(e).__name__}: {e}")
PY

echo
echo "## JSON mustache expression extraction"
python3 - <<'PY'
import json
from pathlib import Path
p = Path("/home/jailuser/git/plugins/MicrosoftPurview/v1/dataStreams/searchAssets.json")
text = p.read_text()
print(text)
PY

Repository: squaredup/plugins

Length of output: 8770


Clamp limit to the Purview search query maximum.

This UI field can send negative, fractional, or oversized values to datamap/api/search/query, which returns up to 1,000 per page. Clamp the coerced number to 1000 before forwarding it, and consider constraining the UI number field between 1 and 1000.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/MicrosoftPurview/v1/dataStreams/searchAssets.json` around lines 39 -
42, Update the postBody limit expression in the Purview search request to coerce
the input, constrain it to the valid 1–1000 range, and forward at most 1000
while preserving the existing default behavior. Also constrain the associated UI
number field, if present in the diff, with minimum 1 and maximum 1000.

Comment on lines +2 to +50
"steps": [
{
"name": "collections",
"dataStream": { "name": "collections" },
"timeframe": "none",
"objectMapping": {
"id": "name",
"name": "displayName",
"type": "sourceType",
"properties": [
"collectionName",
{ "parentCollection": "parentCollectionName" },
"description"
]
}
},
{
"name": "dataSources",
"dataStream": { "name": "listDataSources" },
"timeframe": "none",
"objectMapping": {
"id": "name",
"name": "name",
"type": "sourceType",
"properties": [
"kind",
"collection",
"endpoint",
"resourceGroup",
"subscriptionId"
]
}
},
{
"name": "governanceDomains",
"dataStream": { "name": "governanceDomains" },
"timeframe": "none",
"objectMapping": {
"id": "id",
"name": "name",
"type": "sourceType",
"properties": [
"description",
"type",
"status"
]
}
}
]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Implement scan indexing before advertising scan objects.

The index definition imports only collections, data sources, and governance domains; therefore no scan object can enter the graph despite the README claiming scans are indexed.

  • plugins/MicrosoftPurview/v1/indexDefinitions/default.json#L2-L50: add an import step for the scan stream with stable ID, label, and Purview Scan source type.
  • plugins/MicrosoftPurview/v1/metadata.json#L24-L28: add Purview Scan to objectTypes.
  • plugins/MicrosoftPurview/v1/docs/README.md#L7-L7: retain the scan-indexing claim only after the import is implemented.
  • plugins/MicrosoftPurview/v1/docs/README.md#L63-L70: retain the Purview Scan object-type entry only after the import is implemented.
📍 Affects 3 files
  • plugins/MicrosoftPurview/v1/indexDefinitions/default.json#L2-L50 (this comment)
  • plugins/MicrosoftPurview/v1/metadata.json#L24-L28
  • plugins/MicrosoftPurview/v1/docs/README.md#L7-L7
  • plugins/MicrosoftPurview/v1/docs/README.md#L63-L70
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/MicrosoftPurview/v1/indexDefinitions/default.json` around lines 2 -
50, Implement scan indexing by adding a scan-stream import step with a stable
ID, scan label, and “Purview Scan” source type in
plugins/MicrosoftPurview/v1/indexDefinitions/default.json lines 2-50; add
“Purview Scan” to objectTypes in plugins/MicrosoftPurview/v1/metadata.json lines
24-28, and retain the corresponding scan-indexing and object-type documentation
in plugins/MicrosoftPurview/v1/docs/README.md lines 7-7 and 63-70.

Comment on lines +45 to +52
"baseUrl": "https://{{accountName}}.purview.azure.com/",
"authMode": "oauth2",
"oauth2GrantType": "clientCredentials",
"oauth2TokenUrl": "https://login.microsoftonline.com/{{tenantId}}/oauth2/v2.0/token",
"oauth2ClientId": "{{clientId}}",
"oauth2ClientSecret": "{{clientSecret}}",
"oauth2ClientSecretLocationDuringAuth": "body",
"oauth2Scope": "https://purview.azure.net/.default",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Files:"
git ls-files | rg 'plugins/MicrosoftPurview/v1/(metadata\.json|governanceDomains\.json)|metadata\.json$|governanceDomains\.json$' || true

echo
echo "Relevant MicrosoftPurview v1 metadata:"
sed -n '1,120p' plugins/MicrosoftPurview/v1/metadata.json

echo
echo "Relevant governanceDomains references:"
rg -n "governanceDomains|businessDomain|unified catalog|api\.purview-service|oauth2|baseUrl|objectTypes" plugins/MicrosoftPurview/v1 -S

echo
echo "GovernanceDomains JSON outline/content if present:"
if [ -f plugins/MicrosoftPurview/v1/governanceDomains.json ]; then
  wc -l plugins/MicrosoftPurview/v1/governanceDomains.json
  sed -n '1,240p' plugins/MicrosoftGivernanceDomains.json 2>/dev/null || sed -n '1,240p' plugins/MicrosoftPurview/v1/governanceDomains.json
fi

Repository: squaredup/plugins

Length of output: 5085


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Files:"
git ls-files | rg 'plugins/MicrosoftPurview/v1/(metadata\.json|governanceDomains\.json)|metadata\.json$|governanceDomains\.json$' || true

echo
echo "Relevant MicrosoftPurview v1 metadata:"
sed -n '1,120p' plugins/MicrosoftPurview/v1/metadata.json

echo
echo "Relevant governanceDomains references:"
rg -n "governanceDomains|businessDomain|unified catalog|api\.purview-service|oauth2|baseUrl|objectTypes" plugins/MicrosoftPurview/v1 -S

echo
echo "GovernanceDomains JSON outline/content if present:"
if [ -f plugins/MicrosoftPurview/v1/governanceDomains.json ]; then
  wc -l plugins/MicrosoftPurview/v1/governanceDomains.json
  sed -n '1,240p' plugins/MicrosoftPurview/v1/governanceDomains.json
fi

Repository: squaredup/plugins

Length of output: 5085


🌐 Web query:

Microsoft Purview Unified Catalog enumerate business domains REST endpoint api.purview-service.microsoft.com

💡 Result:

The REST API endpoint to enumerate business domains in the Microsoft Purview Unified Catalog is: GET {endpoint}/datagovernance/catalog/businessdomains?api-version={api-version} The base {endpoint} is typically https://api.purview-service.microsoft.com/ [1]. Key details for this operation include: - HTTP Method: GET [1] - Query Parameters: - api-version (Required): The version of the API to use (e.g., 2026-03-20-preview) [2][1]. - $skipToken (Optional): Used for pagination [1]. - writeOnly (Optional): A boolean parameter used for write-obligation filtering [1]. Authentication for this endpoint requires an OAuth2 bearer token obtained from Microsoft Entra ID with the appropriate scope (typically https://purview.azure.net/.default) [1][3]. You must include this token in the authorization header of your request [4]. For further implementation details, refer to the official Microsoft documentation for the Purview Unified Catalog API [2][5].

Citations:


🌐 Web query:

Microsoft Purview REST API authenticate token scope https://purview.azure.net/.default client_credentials

💡 Result:

To authenticate to the Microsoft Purview REST API using the OAuth 2.0 client credentials flow, you must request an access token from the Microsoft identity platform [1]. The appropriate scope to use for this request is https://purview.azure.net/.default [2][3][4]. When using the client credentials grant type, the.default scope is required to refer generically to the Microsoft Purview resource, ensuring all configured application permissions are included in the token [3]. Key details for the authentication request: - Grant Type: client_credentials [5][6][1] - Scope: https://purview.azure.net/.default [2][3][4] - Endpoint: The token endpoint is https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token [2][1]. Older documentation or legacy implementations may refer to the resource parameter (e.g., resource=https://purview.azure.net) instead of the scope parameter [5][6][7]. However, when using the v2.0 endpoint and modern authentication practices, the scope parameter set to https://purview.azure.net/.default is the standard approach [2][3]. For development, if you are using the Azure SDK for Python, the library handles the underlying token acquisition automatically when you use the ClientSecretCredential class [8].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "All MicrosoftPurview v1 files:"
git ls-files plugins/MicrosoftPurview/v1 | sed -n '1,160p'

echo
echo "dataStreams governance domains content and JS:"
sed -n '1,180p' plugins/MicrosoftPurview/v1/dataStreams/governanceDomains.json
echo
if [ -f plugins/MicrosoftPurview/v1/dataStreams/governanceDomains.js ]; then
  wc -l plugins/MicrosoftPurview/v1/dataStreams/governanceDomains.js
  sed -n '1,220p' plugins/MicrosoftPurview/v1/dataStreams/governanceDomains.js
else
  echo "governanceDomains.js not present"
fi

echo
echo "All relative endpoint definitions:"
rm -rf /tmp/purview-ends
git ls-files plugins/MicrosoftPurview/v1 | while read -r f; do
  case "$f" in
    *.json) rg -n '"url"' "$f" /tmp/purview-ends 2>/dev/null || true ;;
    *.js) rg -n "fetch\\(|/get|/search|url:|url =|apiVersion|endpoint" "$f" || true ;;
  esac
done

echo
echo "Metadata/base configs across Purview plugin:"
python3 - <<'PY'
import json, pathlib
for p in sorted(pathlib.Path('plugins/MicrosoftPurview/v1').rglob('metadata.json')):
    print(f'--- {p} ---')
    with p.open() as fh:
        data=json.load(fh)
    base=data.get('base')
    print(json.dumps(base, indent=2, default=str))
PY

Repository: squaredup/plugins

Length of output: 6125


🌐 Web query:

Azure REST API base query format /?api-version not included in URL

💡 Result:

The api-version query parameter is a mandatory requirement for Azure REST API operations [1][2][3]. According to official Microsoft Azure REST API guidelines, every request sent to an Azure service must include this parameter in the URL [2][3]. If a request omits the api-version parameter, the service will return an HTTP 400 Bad Request error with the error code MissingApiVersionParameter and the message: The api-version query parameter (?api-version=) is required for all requests [2][3][4]. Because this parameter is a fundamental part of the API contract, it cannot be excluded from the URL [2][3]. Azure services use this versioning scheme (typically in YYYY-MM-DD format) to ensure that clients interact with a stable and expected version of the service [1][2][3]. When using tools or SDKs, this parameter is generally appended to the request automatically [1]. If you are constructing manual REST calls, you must explicitly include it, for example: https://management.azure.com/subscriptions?api-version=2020-01-01 [1]

Citations:


🌐 Web query:

site:learn.microsoft.com/en-us/rest/api/purview REST UriFormat BaseUriQueryApiVersion Azure REST API guidelines

💡 Result:

According to the Azure REST API guidelines, REST API URI structures are standardized to ensure consistency and predictability across services [1]. Base URI and Path Structure The base URI generally consists of a service endpoint (often a hostname or a combined subscription/resource group path) followed by the resource hierarchy [2][3][4]. Resource paths should be nouns representing the resource, and they should be hierarchical in nature [3][4]. API Versioning The api-version parameter is a mandatory query parameter in Azure REST APIs [2][5][3][4][1]. It is used to specify the version of the API contract the client wishes to interact with, ensuring backward compatibility and allowing for non-breaking API evolution [2][5][6]. Format Requirements 1. URI Format: URIs must be consistently formatted, typically using forward slashes to separate resource segments. Path parameters are enclosed in curly braces (e.g., {resourceName}) to indicate they are dynamic [2][3][4]. 2. Query Parameters: Parameters that modify the request, such as api-version, are appended to the path following a question mark (?) [2][5][6]. Multiple query parameters are separated by an ampersand (&) [6]. 3. Consistency: Azure guidelines emphasize using standard HTTP methods (GET, POST, PUT, DELETE, PATCH) correctly and maintaining consistent casing and naming conventions throughout the API surface [1]. For detailed implementation and best practices, Microsoft maintains the Azure REST API guidelines which serve as the authoritative reference for service design [1].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Data stream definitions that use relative endpoint paths:"
python3 - <<'PY'
import json, pathlib
fields={'endpointPath','baseUrl','baseDataSourceName'}
for p in sorted(pathlib.Path('plugins/MicrosoftPurview/v1/dataStreams').glob('*.json')):
    try:
        data=json.loads(p.read_text())
    except Exception as e:
        print(f"--- parse error {p}: {e} ---")
        continue
    vals={k:data.get(k) for k in fields}
    if any(vals.values()):
        print(f"--- {p.name} ---")
        for k,v in vals.items():
            print(f"  {k}: {v}")
PY

echo
echo "All fetch/endpoint construction references in Purview scripts:"
rg -n "fetch\\(|new URL|URL\\(|requestPath|body\\[\\]|\\?api-version|datagovernance|businessdomains|glossary|terms|api.purview-service|purview.azure.com|purview.azure.net" plugins/MicrosoftPurview/v1/dataStreams/scripts plugins/MicrosoftPurview/v1/dataStreams -S

Repository: squaredup/plugins

Length of output: 3654


Route Unified Catalog streams through their required endpoint.

governanceDomains.json and glossaryTerms.json define relative Unified Catalog paths, but the plugin base URL points at the account-scoped endpoint. Add a separate authenticated base configuration for https://api.purview-service.microsoft.com/ and switch those streams to it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/MicrosoftPurview/v1/metadata.json` around lines 45 - 52, The
Microsoft Purview metadata configuration currently routes all streams through
the account-scoped baseUrl. Add a separate authenticated base configuration for
https://api.purview-service.microsoft.com/ using the existing OAuth2 settings,
then update the governanceDomains and glossaryTerms stream definitions to
reference that base while leaving other streams on the account-scoped endpoint.

Comment on lines +12 to +37
{
"type": "text",
"name": "tenantId",
"label": "Directory (tenant) ID",
"placeholder": "Enter a directory (tenant) ID",
"validation": {
"required": true
}
},
{
"type": "text",
"name": "clientId",
"label": "Application (client) ID",
"placeholder": "Enter an application (client) ID",
"validation": {
"required": true
}
},
{
"type": "password",
"name": "clientSecret",
"label": "Client secret",
"placeholder": "Enter a client secret",
"validation": {
"required": true
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add example placeholders and credential help text.

Replace the generic ID placeholders with example GUIDs and add concise help explaining where to obtain the tenant ID, client ID, and secret value. This makes the setup form self-contained.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/MicrosoftPurview/v1/ui.json` around lines 12 - 37, Update the
tenantId, clientId, and clientSecret fields in the UI configuration with example
GUID-based placeholders for the IDs and concise help text describing where to
obtain each credential. Preserve the existing labels, field types, and required
validation.

Sources: Coding guidelines, Learnings

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant