dx-org-analyze
Compare two Salesforce orgs side-by-side and produce a comparison report with drift score, or analyze a single org to produce an inventory covering …
它会碰到什么
这个仓库里自带 2 个测试样本文件(有些技能仓会放故意的恶意样本做演示),它们不计入上面的能力与命中。
逐条看命中(3 条严重或高危)
- 高
scripts/collect_org_data.py:45exec-spawnresult = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
- 高
scripts/collect_org_data.py:588exec-spawnresult = subprocess.run(
- 高
tests/test_compute_diff.sh:14fs-destructivetrap "rm -rf $TMPDIR" EXIT
这一栏是扫描器报的事实,不是结论。命中多不等于有毒(安全工具、规则库、示例脚本本来就会包含危险写法),命中少也不等于干净。它和你手上的凭据、文件、网络有什么关系,需要你自己看。
技能内容
Tool Restrictions
Use ONLY the Bash tool to execute all sf CLI commands and Python scripts. Always include --json for sf commands. Do NOT use mcp__salesforce_dx__* tools.
Output artifacts for eval/testing: When an output directory is available, write results there. After executing the skill: (1) if the user specified an output path, write there immediately; (2) otherwise run [ -d force-app/main/adk-eval-output/ ] && echo 'force-app/main/adk-eval-output' to detect the eval directory; (3) write the full JSON result to <output-dir>/dx-org-analyze-result.json and the markdown report to <output-dir>/dx-org-analyze-result.md.
Data Access Hierarchy
When querying org data, always follow this priority order:
- SF CLI commands — Preferred. Use
sf org list metadata-types,sf org list metadata,sf org display,sf data query,sf limits api display, etc. - Direct REST/Tooling API calls — Last resort, only when SF CLI cannot provide the data.
Never bypass this hierarchy. If an SF CLI command exists for the operation, use it even if a direct API call would be simpler.
Authentication Rules
- All authentication MUST go through SF CLI (
sf org login web,sf org login jwt,sf org login access-token). - Never accept raw credentials (username + password), session IDs, or access tokens directly from the user.
- The collection script obtains its access token exclusively via
sf org display --json.
Workflow
Step 0: List Authenticated Orgs
Run this command to discover all authenticated orgs:
sf org list --json --skip-connection-status
Parse the JSON output. Collect orgs from all buckets (devHubs, nonScratchOrgs, scratchOrgs, sandboxes, other). Present authenticated orgs in a readable table:
| # | Alias | Username | Instance URL | Org ID | Type |
|---|-------|----------|--------------|--------|------|
If fewer than 2 orgs are authenticated but at least 1 is available, offer the single-org introspect mode (see Introspect Workflow below). If no orgs are authenticated, STOP and advise:
> You need at least 1 authenticated org. Run sf org login web --alias <name> to authenticate.
If the user explicitly requests a single-org introspection or inventory, use the Introspect Workflow regardless of how many orgs are available.
Step 1: User Selects Two Orgs
Ask the user to select two orgs from the list. Both must be explicitly named — do NOT allow implicit/default orgs.
> Select two orgs to compare. Which is the source (reference/expected state)? Which is the target (to compare against)?
Accept: alias, username, or number from the list. Resolve each selection to a concrete username. If an org lacks an alias, prompt the user to assign one. Confirm:
> Comparing:
> - Source: <alias> (<username>)
> - Target: <alias> (<username>)
Step 2: Validate Connectivity
For each org, confirm reachability with a lightweight query that does not expose secrets:
sf data query --target-org <alias-or-username> --query "SELECT Id FROM Organization LIMIT 1" --json
If the query succeeds (exit 0 and a record is returned), the org is connected. If it fails with INVALID_SESSION_ID or auth errors:
sf org login web --alias <alias>
Step 3: Collect Data (per org)
Generate a unique run ID and run the collection script for each org:
RUN_ID=$(date +%Y%m%d-%H%M%S)
python3 ./scripts/collect_org_data.py \
--org-alias "$SOURCE_ORG" \
--output /tmp/dx-org-comparison-${RUN_ID}-source
python3 ./scripts/collect_org_data.py \
--org-alias "$TARGET_ORG" \
--output /tmp/dx-org-comparison-${RUN_ID}-target
Exit codes: 0 = success, 1 = fatal error (report stderr to user), 2 = session expired (re-authenticate Step 2 and retry).
For details on what the collection script gathers, see references/collection-details.md.
Step 4: Compute Diff and Report
python3 ./scripts/compute_diff.py \
--org-a /tmp/dx-org-comparison-${RUN_ID}-source \
--org-b /tmp/dx-org-comparison-${RUN_ID}-target \
--output /tmp/dx-org-comparison-${RUN_ID} \
--format both \
--org-a-label "Source" \
--org-b-label "Target"
Use --show-shared if the user wants shared components listed in detail.
Step 5: Present Results
Read /tmp/dx-org-comparison-${RUN_ID}.md and present to the user. If the user asks follow-up questions, use /tmp/dx-org-comparison-${RUN_ID}.json for data lookups. Then resolve the output directory and copy both files there:
OUTPUT_DIR=""
if [ -n "$USER_OUTPUT_PATH" ]; then
OUTPUT_DIR="$USER_OUTPUT_PATH"
elif [ -d "force-app/main/adk-eval-output" ]; then
OUTPUT_DIR="force-app/main/adk-eval-output"
fi
if [ -n "$OUTPUT_DIR" ]; then
cp /tmp/dx-org-comparison-${RUN_ID}.json "$OUTPUT_DIR/dx-org-analyze-result.json"
cp /tmp/dx-org-comparison-${RUN_ID}.md "$OUTPUT_DIR/dx-org-analyze-result.md"
fi
Introspect Workflow (Single-Org Mode)
Use this workflow when the user wants to inspect a single org's configuration, or when only one org is authenticated.
Introspect Step 1: Validate Connectivity
sf data query --target-org <alias-or-username> --query "SELECT Id FROM Organization LIMIT 1" --json
Introspect Step 2: Collect Data
RUN_ID=$(date +%Y%m%d-%H%M%S)
python3 ./scripts/collect_org_data.py \
--org-alias "$ORG" \
--output /tmp/dx-org-analysis-${RUN_ID}
Introspect Step 3: Generate Report
python3 ./scripts/introspect_org.py \
--org /tmp/dx-org-analysis-${RUN_ID} \
--output /tmp/dx-org-analysis-${RUN_ID} \
--format both \
--label "OrgName"
Introspect Step 4: Present Results
Read /tmp/dx-org-analysis-${RUN_ID}.md and present to the user. The report covers: metadata inventory, org settings, org limits, installed packages, licenses, system permissions, and deep data records. Then resolve the output directory and copy both files there:
OUTPUT_DIR=""
if [ -n "$USER_OUTPUT_PATH" ]; then
OUTPUT_DIR="$USER_OUTPUT_PATH"
elif [ -d "force-app/main/adk-eval-output" ]; then
OUTPUT_DIR="force-app/main/adk-eval-output"
fi
if [ -n "$OUTPUT_DIR" ]; then
cp /tmp/dx-org-analysis-${RUN_ID}.json "$OUTPUT_DIR/dx-org-analyze-result.json"
cp /tmp/dx-org-analysis-${RUN_ID}.md "$OUTPUT_DIR/dx-org-analyze-result.md"
fi
Report Structure
The generated report includes:
- Drift Score — Weighted overall score (60% metadata, 30% permissions, 10% profiles) with severity level (LOW/MODERATE/HIGH/CRITICAL)
- Summary Statistics — Counts per metadata type with Identical/Different columns from deep data
- Metadata Components by Type — Only-in-Source, only-in-Target, shared per type
- Profiles — Shared, source-only, target-only
- Installed Packages — Version comparison, only-in-Source, only-in-Target
- Package Components — Namespaced components grouped by namespace
- Org Permissions — Boolean enabled/disabled diffs by category, plus value diffs
- System Permissions — PermissionsXxx fields on PermissionSet, per-set diffs
- Org Values & Limits — Grouped by Identity, Storage, API, Feature Limits
- Licenses — User, Permission Set, Package license quantity diffs
- Deep Data — Content-level diffs for Apex, Flows, Validation Rules, Custom Fields, etc.
Rules / Constraints
| Constraint | Rationale |
|-----------|-----------|
| Always use --json with sf commands | Structured output for reliable parsing |
| Resolve orgs to usernames, not aliases | Aliases can be ambiguous; usernames are unique |
| Skip expired and disconnected orgs | Cannot query metadata from inaccessible orgs |
| Read-only — never deploy or modify | This skill compares only, never mutates either org |
| SF CLI auth only | All authentication through SF CLI credential store |
| Both orgs must be explicit | Never compare unnamed or implicit/default orgs |
Troubleshooting
| Issue | Resolution |
|-------|------------|
| "No org found for \<alias\>" | Org not authenticated — run sf org login web --alias <name> |
| Fewer than 2 authenticated orgs | Authenticate additional orgs before comparing |
| "INVALID_SESSION_ID" or auth errors | Session expired — re-run sf org login web --alias <name> |
| Collection script exits with code 2 | Session expired — re-authenticate and retry |
| API limit errors during metadata listing | Use --skip-deep-data for a faster pass with less detail |
| Edition differences (DE vs EE) | Many differences are edition-inherent, not configuration drift |
| Large orgs timeout on deep data | Use --skip-deep-data flag; run full deep data on targeted follow-ups |
Cross-Skill Integration
| Need | Delegate to |
|------|-------------|
| Retrieve specific metadata from an org | platform-metadata-retrieve |
| Deploy metadata to an org | platform-metadata-deploy |
| Create a scratch org for comparison | dx-org-manage |
| Switch default org after comparison | dx-org-switch |
Reference File Index
| File | When to read |
|------|-------------|
| references/collection-details.md | For details on what the collection script gathers and how |
| references/report-format.md | For drift score formula and report section details |
| scripts/collect_org_data.py | Data collection script (per org) |
| scripts/compute_diff.py | Diff computation and report generation script |
| scripts/introspect_org.py | Single-org introspection report script |
想直接用这个技能?
本站把开放许可(MIT / Apache 等)的技能按仓库打包整理到网盘,点一下转存到你自己的网盘,不用一个个从 GitHub 拉。许可未声明的技能只给原始仓库链接,不打包。
它属于哪个仓库
同一个仓库里的其他技能
- commerce-b2b-open-code-components-integrate
- commerce-b2b-open-code-components-replace
- dx-devops-conflict-resolve
- dx-devops-pipeline-manage
- dx-devops-test-failures-analyze
- dx-devops-test-pipeline-configure
- dx-devops-test-suite-assignments-configure
- dx-devops-test-suite-run
- dx-devops-work-item-manage
- dx-app-analytics-query
- platform-agentexchange-partner-offers-configure
- automation-sandbox-post-copy-config-generate