Skip to content

feat: unify RBAC under txc security, add txc governance (environment groups & rule-based policies) - #180

Open
TomProkop wants to merge 8 commits into
masterfrom
feat/environment-groups-policy
Open

feat: unify RBAC under txc security, add txc governance (environment groups & rule-based policies)#180
TomProkop wants to merge 8 commits into
masterfrom
feat/environment-groups-policy

Conversation

@TomProkop

Copy link
Copy Markdown
Member

Summary

Introduces a consistent, MECE command taxonomy for identity/access and tenant-governance concerns:

  • txc security (renamed from txc tenant) — unifies all RBAC (users, service principals, teams, roles, Entra groups) for both the tenant and a single Dataverse environment behind one uniform --environment <id> scope flag.
  • txc governance (new) — tenant-wide governance configuration that organizes multiple environments:
    • environment-group — CRUD, environment membership, and RBAC role assignments held directly on the group.
    • policy-rule — the modern rule-based-policy framework (replacing classic DLP), targeting the confirmed Advanced Connector Policy rule type via a friendly --allow-connector shorthand, plus create/update/remove-rule/assign/assignment-list.
  • txc environment stays scoped to ALM/schema/data for a connected org — no RBAC commands.

See docs/command-taxonomy.md for the full rationale and Skills/security-roles.md / Skills/governance-workflow.md for end-to-end worked sequences.

Notable design decisions

  • Environment-group role assignments use Microsoft's dedicated authorization/environmentGroups/{id}/roleAssignments endpoints (not the generic tenant-scope-query endpoint) — confirmed via REST API research after an initial wrong assumption.
  • policy-rule deliberately does not expose delete-policy or unassign-assignment commands — the underlying API doesn't support them as of this writing. This is documented on the command descriptions and on IPowerPlatformPolicyRuleClient, with the closest supported alternative (--exclude-environment on assign) called out instead of faking it.
  • No back-compat shims, no dead code: txc tenant is fully renamed to txc security, not aliased.

Testing

  • Full solution build: clean, 0 errors.
  • Full unit test suite: 734/734 passing (no regressions).
  • New dedicated tests: EnvironmentGroupCliCommandTests, EnvironmentGroupRoleCliCommandTests, PolicyRuleCliCommandTests (list/get/create/update/remove-rule/assign/assignment-list and their validation-error paths).

TomProkop and others added 8 commits July 17, 2026 17:30
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ance/environment-group

- Migrate txc environment user/service-principal/team/role into txc security
  with a uniform --environment <id> scope flag:
  - security user/service-principal: tenant-wide by default, switch to
    Dataverse environment scope when --environment is resolved (explicit or
    active connection). role list combines tenant + environment sections
    when scoped; role catalog list switches instead of combining.
  - security team: Dataverse-only, --environment is required (no tenant
    equivalent).
  - security group: unchanged, tenant-only, no flag.
- Remove all RBAC commands from txc environment; it is now ALM/data/schema
  only. Delete EnvironmentPrincipalCommandSupport and all old
  Environment/{User,ServicePrincipal,Team,Role} command files/tests.
- Add new txc governance top-level command with environment-group
  (list/get/create/update/delete/environment add/remove) CRUD, backed by a
  new PowerPlatformEnvironmentGroupClient with async operation polling for
  environment add/remove. Governance core contracts also define the
  environment-group role-assignment and policy-rule types for follow-up work.
- Fix a layering violation introduced mid-migration where the Control-layer
  EnvironmentUserProvisioningService referenced the Runtime-layer
  DataverseScopedCommandSupport; environment scope resolution now happens
  inline via IConfigurationResolver + IPowerPlatformEnvironmentCatalog.
- Fix test regressions: SecurityCommandTestHost.TestContext() no longer
  defaults EnvironmentType to null (which tripped the production-guard on
  tenant-only destructive commands); ResolveRequiredEnvironmentScopeAsync now
  throws ConfigurationResolutionException so callers get ExitValidationError
  instead of a generic ExitError.
Add GovernanceCommandTestHost (in-memory fake IPowerPlatformEnvironmentGroupClient)
and CLI-level tests covering list/get/create/update/delete/environment
add/remove, including display-name ambiguity, not-found, and 409-conflict
error mapping. Also fixes EnvironmentGroupCommandSupport.ResolveAsync to
throw ArgumentException (mapped to ExitValidationError by the base command
pipeline) instead of InvalidOperationException (which was falling through
to the generic ExitError path).
Adds PowerPlatformEnvironmentGroupRoleClient implementing
IPowerPlatformEnvironmentGroupRoleClient over the dedicated
authorization/environmentGroups/{id}/roleAssignments REST endpoints
(confirmed via official Microsoft Learn REST API reference - these are
NOT reachable through the generic authorization/roleAssignments?scope=
query filter used for tenant-scoped assignments; environment-group
role assignments use dedicated path-routed endpoints with no scope
field in the request body).

- PowerPlatformRbacClient: replaced the speculative generic
  scope-based methods with two parallel, doc-confirmed code paths -
  tenant assignments (generic endpoint + scope in body) and
  environment-group assignments (dedicated path + no scope in body) -
  sharing only the list-paging/JSON-parsing/HTTP-send core helpers.
- SecurityRoleResolver.ResolvePrincipalAsync widened to public so the
  Governance feature can reuse Graph-backed principal resolution
  without duplicating it.
- Registered IPowerPlatformEnvironmentGroupRoleClient in DI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds CLI commands to grant, list, and revoke RBAC role assignments
(Owner/Contributor/Reader/RBAC Administrator, etc.) directly on an
environment group - applying to every environment currently in the
group and any added later.

- EnvironmentGroupRoleCommandSupport: reuses SecurityRoleResolver's
  Graph-backed principal resolution and PowerPlatformRbacClient's role
  catalog, matching the exact convention already used by
  'txc security group role'. Add is idempotent (no-op if the exact
  principal+role assignment already exists); Remove deletes every
  matching assignment.
- EnvironmentGroupRoleListCliCommand / -AddCliCommand / -RemoveCliCommand
  wired under 'txc governance environment-group role'.
- Unit tests with a queued fake-HTTP-backed SecurityRoleResolver/
  PowerPlatformRbacClient (mirrors SecurityCommandTestHost) plus an
  in-memory fake IPowerPlatformEnvironmentGroupRoleClient - covering
  list, add (group and user principals), idempotent add, unknown-role
  validation, remove, and unknown-group validation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Redesigns PolicyRuleContracts.cs against the confirmed
governance/ruleBasedPolicies REST schema (api-version 2024-10-01,
verified against the official Microsoft Learn REST API reference)
instead of the previously-speculative untyped contracts:

- PowerPlatformPolicy / PowerPlatformPolicyRuleSet: confirmed field
  names (id, name, tenantId, lastModified, ruleSetCount, ruleSets[].
  {id,version,inputs}).
- PowerPlatformPolicyBehaviorType / PowerPlatformPolicyAssignmentResourceType
  converted from placeholder string/enum guesses to the confirmed enum
  value sets (Include/Exclude/NotSpecified,
  EnvironmentGroup/Environment/Tenant/NotSpecified).
- Added PowerPlatformAdvancedConnectorPolicyInputs /
  PowerPlatformAllowedConnectorRule: a strongly-typed helper for the
  one rule set type whose 'inputs' shape is confirmed
  (ConnectorManagement / Advanced Connector Policy), while other rule
  types remain raw JSON until their shapes are confirmed too.
- IPowerPlatformPolicyRuleClient deliberately does NOT expose
  Delete/Unassign - the confirmed REST API surface has no such
  operations (verified against the full Rule Based Policies operation
  list); only RemoveRuleSetAsync (removing one rule set from a policy)
  is real. Documented explicitly rather than faking these with
  workarounds.

Implements PowerPlatformPolicyRuleClient over
api.powerplatform.com/governance/ruleBasedPolicies, following the same
HTTP/JSON-parsing conventions as PowerPlatformEnvironmentGroupClient.
Registered in DI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Implements the full CLI surface for rule-based policies under txc
governance policy-rule: list/get/create/update/remove-rule/assign/
assignment list. --allow-connector gives a friendly shorthand for
building ConnectorManagement (Advanced Connector Policy) rule sets;
--rule-set-inputs-json covers any other rule type once its shape is
confirmed. No delete or unassign commands are exposed, matching the
confirmed API gap documented on IPowerPlatformPolicyRuleClient -
policy-rule's own command description explains this and the closest
supported alternative (exclude via a group-wide assignment override).

Adds PolicyRuleCommandTestHost + PolicyRuleCliCommandTests (14 tests
covering list/create/update/remove-rule/assign/assignment-list and
their validation-error paths). Full suite: 734/734 passing.
docs/command-taxonomy.md documents the final environment/security/
governance split: why RBAC is consolidated under txc security via a
uniform --environment scope flag (default to active connection,
required for team, absent for group), why catalog-listing switches
scope while assignment-listing combines it, and why environment-group/
policy-rule live under governance with no scope flag needed. Also
documents the confirmed rule-based-policy API gaps (no delete/
unassign) and the closest supported alternative.

Skills/governance-workflow.md gives the full create-group -> add-
environment -> role-add -> policy-create -> policy-assign sequence
with copy-pasteable commands, so no external Microsoft docs are
needed. Linked from README's detailed-guides line.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant