Skip to content

Beta2 decomposed PermissionSet files can be resolved as the parent component #3621

Description

@MaxHuet

Summary

A Salesforce DX project using decomposePermissionSetBeta2 can fail during source-to-Metadata API conversion when a decomposed Permission Set is resolved from a package directory or manifest.

The resolver can select a child fragment as the Permission Set root. The Permission Set transformer then generates a non-existent synthetic path.

Environment

  • Salesforce CLI: 2.146.3
  • @salesforce/plugin-deploy-retrieve: 13.0.1
  • Node.js: 24.16.0
  • OS: Windows
  • Source behavior: decomposePermissionSetBeta2

The deploy-retrieve plugin declares @salesforce/source-deploy-retrieve with dependency range ^12.32.9.

Reproduction

sfdx-project.json:

{
  "packageDirectories": [
    {
      "path": "force-app",
      "default": true
    }
  ],
  "sourceBehaviorOptions": [
    "decomposePermissionSetBeta2"
  ],
  "sourceApiVersion": "63.0"
}

Source tree:

force-app/main/default/permissionsets/MyPermissionSet/
|-- MyPermissionSet.permissionset-meta.xml
|-- MyPermissionSet.applicationVisibility-meta.xml
|-- MyPermissionSet.classAccess-meta.xml
`-- objectSettings/
    `-- Account.objectSettings-meta.xml

Manifest:

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>MyPermissionSet</members>
        <name>PermissionSet</name>
    </types>
    <version>63.0</version>
</Package>

Command:

sf project deploy start \
  --manifest manifest/package.xml \
  --ignore-conflicts \
  --dry-run

Actual result

The deployment fails before Metadata API execution:

ConversionError: ENOENT: no such file or directory, open
.../permissionsets/MyPermissionSet/objectSettings/Account.permissionset-meta.xml

Expected result

The resolver should identify the parent file:

MyPermissionSet.permissionset-meta.xml

and include all decomposed child fragments in the conversion.

Technical cause

BaseSourceAdapter.parseAsRootMetadataXml() considers a metadata file to be a root when the containing directory name matches the parsed full name.

A child such as MyPermissionSet.applicationVisibility-meta.xml has the same logical name as its parent directory and can therefore be incorrectly classified as the root.

When the root lookup is retried, TreeContainer.find() compares base names without considering the metadata suffix. Files such as MyPermissionSet.classAccess-meta.xml and MyPermissionSet.permissionset-meta.xml are therefore indistinguishable and the first matching file can be returned.

DecomposedPermissionSetTransformer then receives the wrong XML path and constructs the invalid fallback path:

Account.objectSettings-meta.xml
-> Account.permissionset-meta.xml

Proposed resolution

  1. Require the metadata suffix to match the parent type suffix or legacy suffix before accepting a file as the root.
  2. Resolve the root file in ownFolder components by matching the parent suffix, not only the base name.
  3. Add a regression test for a Beta2 Permission Set resolved from its directory.

Validation

The fix is implemented in fork commit:

MaxHuet/source-deploy-retrieve@83ce8bc05

Validation results:

  • yarn build: passed
  • yarn test:only: 1,075 tests passed
  • yarn test:snapshot: 79 tests passed
  • Real decomposed Permission Set resolution: passed
  • Real Permission Set recomposition to Metadata API format: passed

The existing registry completeness test reports unrelated metadata coverage entries missing from the current registry.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions