feat(dar): Granted lifecycle, filters, sort, and self-service create policy#28044
feat(dar): Granted lifecycle, filters, sort, and self-service create policy#28044harshach wants to merge 18 commits into
Conversation
…ate policy Splits the Data Access Request lifecycle into Approved (awaiting grant) and Granted (active access) so the UI can show an "approved – awaiting grant" banner that clears once an admin marks the request as granted. Adds an indexed approvedBy/approvedById/approvedAt on Task, captured at the approve transition through a new direct-persist helper. Introduces a dedicated /v1/tasks/dataAccessRequests endpoint pre-scoped to category=DataAccess with DAR filters (dataset, service, status, requestedBy, approver, accessType) and an asc/desc sort on createdAt; generic /v1/tasks gains service/approver filters too. DataConsumerPolicy now grants Create on resource=task so authenticated non-admins can file a DAR (fixes "operations [Create] not allowed"). Reworks the workflow handler so transitions whose targetTaskStatus is non-terminal (Approved, Granted) don't close the task, and updates CreateTask.isTerminalTaskStatus to allow advancing between Approved → Granted stages. Adds a new "active" statusGroup that includes the DAR lifecycle states while preserving the existing open/closed semantics that Glossary-style workflows depend on. Includes a Postgres + MySQL migration for the indexed approvedById generated column and integration coverage in DataAccessRequestIT spanning the new lifecycle, filters, sorting, approver capture, and the non-admin policy path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
✅ TypeScript Types Auto-UpdatedThe generated TypeScript types have been automatically updated based on JSON schema changes in this PR. |
There was a problem hiding this comment.
Pull request overview
This PR extends the Data Access Request (DAR) task workflow to support a non-terminal Approved → Granted lifecycle, adds a dedicated DAR listing endpoint with richer filtering/sorting, and updates policy + schema/migrations to persist and query approver metadata efficiently.
Changes:
- Added
Grantedtask status plusapprovedBy/approvedById/approvedAtfields, with workflow updates to supportmarkAsGrantedand revoke from both Approved/Granted. - Introduced
GET /v1/tasks/dataAccessRequestswith DAR-scoped filters and offset pagination; expanded generic task filters (approver/aboutService/accessType) and addedactivestatusGroup. - Updated DataConsumer policy to allow authenticated users to create tasks, plus DB migrations to index
approvedByIdfor filtering performance.
Reviewed changes
Copilot reviewed 37 out of 42 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| openmetadata-ui/src/main/resources/ui/src/rest/tasksAPI.ts | Adds Granted, DataAccessType, active statusGroup, and DAR list API typings. |
| openmetadata-ui/src/main/resources/ui/src/hooks/useDataAccessRequest.ts | Switches hook to DAR-specific endpoint and adds “awaiting grant” state for banner/disable logic. |
| openmetadata-ui/src/main/resources/ui/src/components/DataAssets/DataAssetsHeader/DataAssetsHeader.component.tsx | Renders info banner when the current user’s DAR is Approved (awaiting grant). |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json | Adds label/message keys for DAR lifecycle, filters, and banner text. |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-tw.json | Adds corresponding i18n keys for DAR lifecycle, filters, and banner text. |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json | Adds corresponding i18n keys for DAR lifecycle, filters, and banner text. |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/tr-tr.json | Adds corresponding i18n keys for DAR lifecycle, filters, and banner text. |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/th-th.json | Adds corresponding i18n keys for DAR lifecycle, filters, and banner text. |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json | Adds corresponding i18n keys for DAR lifecycle, filters, and banner text. |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-pt.json | Adds corresponding i18n keys for DAR lifecycle, filters, and banner text. |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json | Adds corresponding i18n keys for DAR lifecycle, filters, and banner text. |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/pr-pr.json | Adds corresponding i18n keys for DAR lifecycle, filters, and banner text. |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/nl-nl.json | Adds corresponding i18n keys for DAR lifecycle, filters, and banner text. |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/mr-in.json | Adds corresponding i18n keys for DAR lifecycle, filters, and banner text. |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/ko-kr.json | Adds corresponding i18n keys for DAR lifecycle, filters, and banner text. |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json | Adds corresponding i18n keys for DAR lifecycle, filters, and banner text. |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/he-he.json | Adds corresponding i18n keys for DAR lifecycle, filters, and banner text. |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/gl-es.json | Adds corresponding i18n keys for DAR lifecycle, filters, and banner text. |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json | Adds corresponding i18n keys for DAR lifecycle, filters, and banner text. |
| openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json | Adds corresponding i18n keys for DAR lifecycle, filters, and banner text. |
| openmetadata-spec/src/main/resources/json/schema/entity/tasks/task.json | Adds Granted enum + approver capture fields to Task schema. |
| openmetadata-spec/src/main/resources/json/schema/api/tasks/taskCount.json | Adds approved and granted counters to task count schema. |
| openmetadata-service/src/main/resources/json/data/policy/DataConsumerPolicy.json | Grants authenticated users Create permission on task. |
| openmetadata-service/src/main/resources/json/data/governance/workflows/DataAccessRequestTaskWorkflow.json | Updates DAR workflow stages/transitions for Approved→Granted lifecycle. |
| openmetadata-service/src/main/java/org/openmetadata/service/tasks/TaskWorkflowHandler.java | Captures approver for non-terminal approve transitions; treats Approved/Granted as non-terminal in resolution fallback. |
| openmetadata-service/src/main/java/org/openmetadata/service/resources/tasks/TaskResource.java | Adds new /dataAccessRequests endpoint; expands /tasks filters; extends resolvable statuses. |
| openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TaskRepository.java | Adds DAR list method with offset pagination + createdAt sorting; adds approver persistence helper. |
| openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/ListFilter.java | Adds active statusGroup and new filter conditions (approver/aboutService/accessType). |
| openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/CollectionDAO.java | Extends task count summary and adds DAO queries for createdAt-sorted offset pagination. |
| openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/userTask/CreateTask.java | Treats Approved/Granted as non-terminal statuses. |
| openmetadata-sdk/src/main/java/org/openmetadata/sdk/services/tasks/TaskService.java | Adds SDK helper for /dataAccessRequests endpoint. |
| openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/DataAccessRequestIT.java | Adds/updates IT coverage for Approved→Granted lifecycle, policy, and DAR list filters. |
| openmetadata-integration-tests/pom.xml | Adds test dependencies for PDF/XLSX fixture generation. |
| bootstrap/sql/migrations/native/2.0.1/postgres/schemaChanges.sql | Adds generated approvedbyid column + index for approver filtering (Postgres). |
| bootstrap/sql/migrations/native/2.0.1/mysql/schemaChanges.sql | Adds generated approvedById column + index for approver filtering (MySQL). |
Comments suppressed due to low confidence (1)
openmetadata-ui/src/main/resources/ui/src/hooks/useDataAccessRequest.ts:114
- Same timestamp issue in the stage-based fallback:
isDarApprovalActiveis called withtask.updatedAt ?? task.createdAteven when the task is in the approved/granted stage. This should use the persisted approval timestamp (task.approvedAt) to avoid duration calculations being affected by later transitions.
const stage = (
task.workflowStageDisplayName ??
task.workflowStageId ??
''
).toLowerCase();
if (stage === 'approved' || stage === 'granted') {
const payload = task.payload as
| { duration?: string; expirationDate?: number }
| undefined;
return isDarApprovalActive(
task.updatedAt ?? task.createdAt,
payload?.duration,
payload?.expirationDate
);
…tTaskStatus, document status-group semantics - Replace hardcoded `"approve".equals(transitionId)` checks in TaskWorkflowHandler with a `targetTaskStatus == Approved` helper so the approver-capture path isn't coupled to the workflow JSON's literal transition id. - Document the intentional dual membership of `Approved` in the `active` and `closed` status groups (and in `completedCount` / `approvedCount`): the same status has different lifecycle meanings for Glossary-style workflows (terminal) vs Data Access Requests (awaiting grant), and removing it from `closed` would regress the existing Closed tab for legacy workflows. - Use the persisted `task.approvedAt` (with fallback to updatedAt/createdAt) for `isDarApprovalActive` duration calculations in the DAR hook so later workflow transitions don't shift the apparent approval timestamp. - Add trailing newline to DataConsumerPolicy.json. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…migration, fix CreateTaskTest - /v1/tasks/dataAccessRequests now runs the same `authorizer.authorize(...)` + `EntityUtil.addDomainQueryParam(...)` calls that `listInternal` applies on the generic /v1/tasks endpoint, so the DAR endpoint enforces permissions and domain scoping equivalently. The endpoint still uses offset-based pagination + createdAt sort (so we can't reuse listInternal directly). - Update the statusGroup OpenAPI description and allowableValues to reflect the actual server semantics: 'open' = Open/InProgress/Pending, 'active' = Open/InProgress/Pending/Approved/Granted (DAR-friendly), 'closed' = Approved/Rejected/Completed/Cancelled/Failed/Revoked (keeps Approved for backward compat with non-DAR workflows where Approved is terminal). - Replace the unsupported `ADD COLUMN IF NOT EXISTS` / `ADD KEY IF NOT EXISTS` in the MySQL 2.0.1 migration with information_schema-guarded prepared statements, mirroring the idempotent ALTER pattern used elsewhere in the repo. `ADD KEY IF NOT EXISTS` is not valid MySQL syntax and `ADD COLUMN IF NOT EXISTS` only works on 8.0.29+. - Update CreateTaskTest so the assertions match the new `isTerminalTaskStatus` semantics: Approved and Granted are non-terminal (so the next-stage CreateTask listener can advance the DAR through ApprovedAccess → GrantedAccess); Revoked is terminal. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…resolve guard on availableTransitions
Two review-driven fixes:
1) Add an idempotent ALTER inside bootstrap/sql/migrations/native/2.0.0/
schemaChanges.sql so environments that already executed the 2.0.0 CREATE
TABLE (before the approvedById generated column was inlined) pick up the
new column + index. Fresh installs use the inline definition; existing
2.0.0 deployments get it via the ALTER.
- MySQL: information_schema-guarded prepared statements (MySQL doesn't
reliably support `ADD COLUMN IF NOT EXISTS` across 8.0 versions and has
no `ADD KEY IF NOT EXISTS`).
- Postgres: native `ADD COLUMN IF NOT EXISTS`.
2) Refine TaskResource.validateTaskCanBeResolved so Approved/Granted are
only treated as resolvable when the workflow still exposes available
transitions. Without this guard, terminal-approved workflows like
Glossary or DescriptionUpdate (where Approved is a terminal state and
availableTransitions is empty) would let users / bulk operations
re-resolve already-closed tasks and re-run postUpdate hooks. DAR's
Approved (markAsGranted/revoke) and Granted (revoke) keep working
because their availableTransitions list is non-empty.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… isDarDisabled/isDarAwaitingGrant - bootstrap/sql/migrations/native/2.0.0/postgres/schemaChanges.sql: Move `CREATE INDEX IF NOT EXISTS idx_task_approved_by_id` to run AFTER the `ALTER TABLE ADD COLUMN IF NOT EXISTS approvedbyid` so existing 2.0.0 deployments (whose CREATE TABLE IF NOT EXISTS is a no-op and therefore doesn't add the inlined column) don't fail the CREATE INDEX with "column does not exist". Fresh installs still get both via the CREATE TABLE / first-time CREATE INDEX; existing installs now get the ALTER first, then the index. - openmetadata-ui/.../hooks/useDataAccessRequest.ts: Unify isDarDisabled and isDarAwaitingGrant so both use the same `status || stage` resolution (TaskEntityStatus.Approved/Granted with DarWorkflowStage fallback) and isDarDisabled now uses the persisted `task.approvedAt` for the isDarApprovalActive duration check (falling back to updatedAt/createdAt only for older tasks). Avoids the prior inconsistency where one memo was stage-string-only and the other was status-enum-only, and prevents later workflow transitions (granting) from extending the apparent approval window via updatedAt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… status-wide aggregation `TaskCountSummary` computes `approvedCount`/`grantedCount` purely from `status = 'Approved'/'Granted'` (see CollectionDAO.TaskDAO.getTaskCountSummary), which means terminal-Approved tasks from other workflows (Glossary, DescriptionUpdate, etc.) also land in `approvedCount` — not just DARs awaiting grant. Update the JSON-schema descriptions so they don't claim DAR-only scope and instead state the actual status-based meaning. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
✅ TypeScript Types Auto-UpdatedThe generated TypeScript types have been automatically updated based on JSON schema changes in this PR. |
|
Code Review ✅ Approved 7 resolved / 7 findingsExpands the Data Access Request workflow with 'Granted' and 'Approved' states, enhanced filtering, and updated policies to support end-to-end lifecycle management. Addressed all findings related to status grouping, workflow coupling, migration scripts, and duplicate request prevention. ✅ 7 resolved✅ Bug: 'Approved' status present in both 'active' and 'closed' groups
✅ Quality: Hardcoded 'approve' transition ID couples handler to workflow JSON
✅ Quality: Missing newline at end of DataConsumerPolicy.json
✅ Bug: isDarDisabled missing 'granted' stage — allows duplicate DARs
✅ Quality: Unused TaskEntityStatus import in isDarDisabled after refactor
...and 2 more resolved from earlier reviews OptionsDisplay: compact → Showing less information. Comment with these commands to change:
Was this helpful? React with 👍 / 👎 | Gitar |
|



Describe your changes:
I added a
Grantedstate and filterable list to the Data Access Request workflow, gave authenticated users permission to file a DAR, and fixed the related workflow-handler bugs that surfaced onceApprovedbecame a non-terminal state.Type of change:
High-level design:
Lifecycle. The DAR workflow now goes
Open → Approved (awaiting grant) → Granted (active access) → Revoked, withApprovedandGrantedadded toTaskEntityStatus. The UI hook (useDataAccessRequest) andDataAssetsHeaderrender an info banner while a DAR for the current user is inApproved, and clear it once it transitions toGranted. Approver capture is wired through a newTaskRepository.persistApprover()helper that goes throughstoreEntity+postUpdateso the newapprovedBy/approvedById/approvedAtfields are persisted reliably on both terminal and non-terminal approve transitions.Filters. Added a dedicated
/v1/tasks/dataAccessRequestssub-endpoint that pre-scopes tocategory=DataAccess,type=DataAccessRequestand exposesdataset,service,status,requestedBy,approver,accessType,sortOrder(asc/desc oncreatedAt), plus offset-based pagination. Generic/v1/tasksgainsaboutService,approver, andapproverIdfilters so other task types benefit too. NewListFilterconditions cover the approver (indexedapprovedByIdcolumn with FQN fallback), the service via FQN-hash prefix, andpayload.accessTypevia the existing@ConnectionAwareSqlQueryJSON-extract pattern.Policy. Adds a
DataConsumerPolicy-CreateTask-RulegrantingCreateon resourcetaskto authenticated users, fixing theoperations [Create] not allowederror a non-admin saw when trying to request access.Workflow-handler fixes discovered while writing integration tests:
resolveResolutionTypeno longer mapsApproved/Grantedto a terminalTaskResolutionTypein the fallback switch — the workflow stays alive so the request can later be granted or revoked.CreateTask.isTerminalTaskStatusnow treatsApprovedandGrantedas non-terminal, allowing the next-stage CreateTask to actually update the existing task'sstatus/workflowStageId/availableTransitionsinstead of preserving stale state during themarkAsGrantedtransition.activevalue forstatusGroup(Open + InProgress + Pending + Approved + Granted) so the DAR hook can find "still in progress" requests without altering the existingopen/closedsemantics that Glossary-style workflows depend on.Migration. In
bootstrap/sql/migrations/native/2.0.0/{mysql,postgres}/schemaChanges.sqlthe newapprovedByIdgenerated column +idx_approved_by_idindex are declared inline on thetask_entityCREATE TABLE for fresh installs, and an idempotent guarded ALTER block in the same file attaches the column + index for existing 2.0.0 deployments where the CREATE TABLE IF NOT EXISTS is a no-op (information_schema-guarded prepared statements on MySQL, nativeADD COLUMN IF NOT EXISTSon Postgres). 2.0.0 has not been released yet, so no data backfill is needed.Tests:
Use cases covered
POST /v1/tasks(was previously denied by policy).ApprovedwithapprovedBy/At/ByIdpopulated and bothmarkAsGrantedandrevoketransitions surfaced.GrantedwithapprovedBypreserved.Approved(back out before granting) orGranted(revoke active access) → task ends inRevokedwith aRevokedresolution./v1/tasks/dataAccessRequestshonorsdataset,accessType,status,approverId, andsortOrder=asc|desc, and never leaks non-DAR task types into the list.closedinTaskCount.openCount/completedCount(no regression).Backend integration tests
openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/DataAccessRequestIT.java(8 new + 3 updated test cases). Verified by runningmvn test -pl openmetadata-integration-tests -Dtest='DataAccessRequestIT,TaskResourceIT,IncidentTaskIntegrationIT'— 257 tests pass, 0 failures.Playwright (UI) tests
Manual testing performed
make generateregenerates Pydantic + Java POJOs cleanly after thetask.jsonandtaskCount.jsonschema edits and that the newGrantedenum +approvedBy*fields appear intarget/generated-sources.mvn spotless:applyandyarn ui-checkstyle:changedon the touched files;yarn i18nsynced the 13 new locale keys across all 17 locale files.UI screen recording / screenshots:
Not applicable. The only UI change is an Ant Design
Alertbanner shown when a request is in theApproved(awaiting-grant) state; the dedicated DAR list page is a follow-up.Checklist:
bootstrap/sql/migrations/native/2.0.0/{mysql,postgres}/schemaChanges.sqlfor the indexedapprovedByIdcolumn (inline in the CREATE TABLE for fresh installs, idempotent guarded ALTER for existing 2.0.0 deployments).DataAccessRequestIT) and listed them above.🤖 Generated with Claude Code