@salesforce/afv-skills 1.58.0 → 1.60.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/agentforce-architecture-analyze/SKILL.md +66 -17
- package/skills/agentforce-architecture-analyze/assets/cli/show_access_token.yaml +4 -7
- package/skills/agentforce-architecture-analyze/references/contract.json +1 -1
- package/skills/agentforce-architecture-analyze/scripts/emit_env.py +2 -2
- package/skills/agentforce-architecture-analyze/scripts/main.py +40 -44
- package/skills/agentforce-architecture-analyze/scripts/rest_client.py +11 -3
- package/skills/agentforce-architecture-analyze/scripts/sf_cli.py +77 -10
- package/skills/agentforce-architecture-analyze/scripts/tests/test_end_to_end_fixture.py +1 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_flow_children_inflation.py +1 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_main_pipeline.py +53 -2
- package/skills/agentforce-architecture-analyze/scripts/tests/test_resolve_creds.py +184 -36
- package/skills/agentforce-architecture-analyze/scripts/tests/test_rest_client.py +17 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_sf_cli.py +165 -11
- package/skills/agentforce-architecture-analyze/scripts/tests/test_skill_md_pipeline_block.py +319 -0
- package/skills/agentforce-bot-upgrade/SKILL.md +3 -1
- package/skills/agentforce-d360-analyze/SKILL.md +28 -10
- package/skills/agentforce-d360-analyze/scripts/dc.py +200 -50
- package/skills/agentforce-d360-analyze/scripts/discover_sessions.py +10 -6
- package/skills/agentforce-d360-analyze/scripts/fetch_dc.py +22 -6
- package/skills/agentforce-d360-analyze/scripts/resolve_session.py +21 -13
- package/skills/agentforce-d360-analyze/scripts/tests/test_dc_and_resolve_session.py +298 -76
- package/skills/agentforce-d360-analyze/scripts/tests/test_default_target_org.py +432 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_discover_sessions.py +1 -1
- package/skills/agentforce-d360-analyze/scripts/tests/test_resolve_session_main.py +9 -3
- package/skills/agentforce-d360-analyze/scripts/tests/test_skill_md_prefix_block.py +176 -0
- package/skills/agentforce-generate/SKILL.md +21 -1
- package/skills/agentforce-generate/references/known-issues.md +51 -1
- package/skills/agentforce-generate/references/legacy-nga-regression-eval.md +547 -0
- package/skills/agentforce-generate/references/upgrade-legacy-agent-to-agentscript.md +577 -0
- package/skills/agentforce-generate/scripts/upgrade-legacy-nga-analyze.py +404 -0
- package/skills/agentforce-generate/scripts/upgrade-legacy-nga-run-trials.sh +58 -0
- package/skills/agentforce-persona-generate/SKILL.md +505 -0
- package/skills/agentforce-persona-generate/assets/checklist-template.md +100 -0
- package/skills/agentforce-persona-generate/assets/persona-encoding-template.md +252 -0
- package/skills/agentforce-persona-generate/assets/persona-template.md +229 -0
- package/skills/agentforce-persona-generate/assets/sample-dialog-template.md +50 -0
- package/skills/agentforce-persona-generate/assets/workshop-outline-template.md +97 -0
- package/skills/agentforce-persona-generate/examples/concierge-persona.md +189 -0
- package/skills/agentforce-persona-generate/examples/concierge-sample-dialog.md +70 -0
- package/skills/agentforce-persona-generate/examples/drover-persona.md +194 -0
- package/skills/agentforce-persona-generate/examples/drover-sample-dialog.md +62 -0
- package/skills/agentforce-persona-generate/examples/steady-hand-persona.md +188 -0
- package/skills/agentforce-persona-generate/examples/steady-hand-sample-dialog.md +68 -0
- package/skills/agentforce-persona-generate/examples/yt-persona.md +195 -0
- package/skills/agentforce-persona-generate/examples/yt-sample-dialog.md +66 -0
- package/skills/agentforce-persona-generate/references/attributions.md +36 -0
- package/skills/agentforce-persona-generate/references/interaction-design-notes.md +30 -0
- package/skills/agentforce-persona-generate/references/persona-encoding-guide.md +566 -0
- package/skills/agentforce-persona-generate/references/persona-framework.md +796 -0
- package/skills/agentforce-persona-generate/references/refinement-mappings.md +31 -0
- package/skills/agentforce-persona-generate/references/scoring-rubric.md +58 -0
- package/skills/agentforce-persona-generate/references/voice-catalog.json +2327 -0
- package/skills/agentforce-persona-generate/references/workshop-question-policy.md +90 -0
- package/skills/agentforce-persona-generate/references/workshop-scenario-seeds.md +119 -0
- package/skills/agentforce-persona-generate/scripts/parse_agent_yaml.py +223 -0
- package/skills/consumer-goods-accruals-datakit-deploy/SKILL.md +17 -27
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/setup.js +7 -17
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/00-check-prerequisites.js +47 -63
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/01-download-static-resource.js +10 -13
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/02-replace-org-id.js +46 -46
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/03-deploy-metadata.js +4 -21
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/06-create-dataspace.js +58 -82
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/07-deploy-accruals-reports.js +16 -315
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/08-deploy-ui.js +9 -24
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/09-completion.js +44 -44
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/utils.js +11 -63
- package/skills/consumer-goods-rtr-datacloud-export-configure/SKILL.md +2 -1
- package/skills/consumer-goods-tpe-dashboard-configure/SKILL.md +2 -1
- package/skills/consumer-goods-tpe-dashboard-custom-kpi-configure/SKILL.md +2 -1
- package/skills/consumer-goods-tpe-datakit-deploy/SKILL.md +2 -1
- package/skills/data360-schema-get/SKILL.md +3 -3
- package/skills/design-systems-slds-validate/references/report-format.md +1 -1
- package/skills/dx-app-analytics-query/SKILL.md +8 -8
- package/skills/dx-org-manage/SKILL.md +1 -0
- package/skills/dx-org-shape-manage/SKILL.md +1 -0
- package/skills/dx-org-snapshot-manage/SKILL.md +172 -0
- package/skills/dx-org-snapshot-manage/examples/create_error_output.json +16 -0
- package/skills/dx-org-snapshot-manage/examples/create_success_output.json +19 -0
- package/skills/dx-org-snapshot-manage/examples/delete_output.json +9 -0
- package/skills/dx-org-snapshot-manage/examples/get_output.json +19 -0
- package/skills/dx-org-snapshot-manage/examples/list_output.json +36 -0
- package/skills/dx-org-snapshot-manage/references/cli_flags.md +179 -0
- package/skills/dx-org-snapshot-manage/references/snapshot_usage.md +55 -0
- package/skills/dx-org-trial-expiration-check/SKILL.md +1 -1
- package/skills/dx-org-trial-expiration-check/scripts/check_expiration.sh +2 -2
- package/skills/education-cloud-student-recruitment-agent-configure/SKILL.md +7 -5
- package/skills/education-cloud-student-recruitment-agent-configure/references/prerequisites.md +11 -11
- package/skills/experience-content-media-image-generate/SKILL.md +83 -0
- package/skills/experience-content-media-image-generate/scripts/download-image.sh +84 -0
- package/skills/experience-ui-bundle-app-coordinate/SKILL.md +12 -12
- package/skills/experience-ui-bundle-app-coordinate/references/phase-completion-validation.md +3 -3
- package/skills/experience-ui-bundle-app-coordinate/references/phase-execution-pattern.md +9 -7
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-dangling-refs.mjs +132 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-hosting-target.mjs +62 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-1-complete.mjs +71 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-4-complete.mjs +95 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-6-ready.mjs +78 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-prerequisites.mjs +21 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-sfdx-project.mjs +28 -0
- package/skills/experience-ui-bundle-custom-app-generate/SKILL.md +3 -1
- package/skills/experience-ui-bundle-custom-app-generate/scripts/resolve-uibundle-path.mjs +40 -0
- package/skills/experience-ui-bundle-frontend-generate/SKILL.md +7 -5
- package/skills/experience-ui-bundle-frontend-generate/scripts/check-preconditions.mjs +70 -0
- package/skills/experience-ui-bundle-frontend-generate/scripts/resolve-ui-bundle.mjs +76 -0
- package/skills/experience-ui-bundle-frontend-generate/scripts/verify-rules.mjs +115 -0
- package/skills/experience-ui-bundle-metadata-generate/SKILL.md +7 -3
- package/skills/experience-ui-bundle-metadata-generate/references/angular-metadata-generate.md +1 -1
- package/skills/experience-ui-bundle-metadata-generate/references/react-metadata-generate.md +1 -1
- package/skills/experience-ui-bundle-metadata-generate/scripts/check-api-version.mjs +43 -0
- package/skills/experience-ui-bundle-metadata-generate/scripts/detect-framework.mjs +131 -0
- package/skills/experience-ui-bundle-metadata-generate/scripts/verify-bundle-location.mjs +152 -0
- package/skills/experience-ui-bundle-mfa-configure/references/branding.md +10 -6
- package/skills/external-diagram-mermaid-generate/SKILL.md +12 -12
- package/skills/field-service-data-capture-migrate/references/component-mapping.md +1 -1
- package/skills/field-service-data-capture-migrate/references/fsm-dc-capability-catalog.md +1 -2
- package/skills/field-service-data-capture-migrate/references/known-deploy-errors.md +1 -0
- package/skills/field-service-data-capture-migrate/references/transformer-rules.md +1 -1
- package/skills/field-service-data-capture-migrate/scripts/transform_flow.py +12 -1
- package/skills/field-service-data-capture-migrate/scripts/vendor/build_flow.py +4 -1
- package/skills/field-service-setup-orchestrator-get/SKILL.md +0 -1
- package/skills/insurance-brokerage-agency-billing-configure/SKILL.md +233 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/accounting-setup.md +117 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/billing-rules-config.md +237 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/billing-settings.md +271 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/demo-policy-config.md +138 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/org-defaults.md +64 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/permissions-config.md +226 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/prerequisites.md +142 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/SKILL.md +3 -2
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-execution-state-and-recovery.md +3 -3
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-overview.md +68 -45
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-visit-creation-data.md +17 -18
- package/skills/life-sciences-kam-coordinate/references/stage-5-data-and-plan-templates-overview.md +16 -3
- package/skills/life-sciences-kam-coordinate/references/stage-5-data-creation-data.md +16 -13
- package/skills/marketing-message-test/SKILL.md +194 -0
- package/skills/marketing-message-test/references/api-contract.md +333 -0
- package/skills/omnistudio-callable-apex-generate/SKILL.md +3 -3
- package/skills/omnistudio-datamapper-generate/SKILL.md +6 -6
- package/skills/omnistudio-datapacks-deploy/SKILL.md +11 -11
- package/skills/omnistudio-dependencies-analyze/SKILL.md +5 -5
- package/skills/omnistudio-epc-catalog-generate/SKILL.md +6 -6
- package/skills/omnistudio-flexcard-generate/SKILL.md +6 -6
- package/skills/omnistudio-integration-procedure-generate/SKILL.md +6 -6
- package/skills/omnistudio-omniscript-generate/SKILL.md +6 -5
- package/skills/platform-apex-logs-debug/SKILL.md +1 -0
- package/skills/platform-metadata-deploy/SKILL.md +1 -0
- package/skills/platform-models-api-configure/SKILL.md +5 -5
- package/skills/platform-soql-query/SKILL.md +1 -0
- package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +17 -6
- package/skills/service-itsm-agentic-setup-incident-sla-configure/SKILL.md +107 -192
- package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone-action.json +6 -6
- package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/milestone-patterns.md +49 -20
- package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/output-templates.md +4 -4
- package/skills/service-itsm-agentic-setup-incident-sla-configure/references/mcp-invocation.md +224 -290
- package/skills/service-itsm-agentic-setup-incident-sla-configure/references/workflow.md +295 -0
- package/skills/service-itsm-incident-priority-configure/SKILL.md +1 -1
- package/skills/service-itsm-slack-itservice-configure/SKILL.md +2 -1
- package/skills/service-itsm-slack-itservice-configure/references/manage-slack-connection.md +2 -2
- package/skills/service-omni-channel-setup-coordinate/SKILL.md +20 -13
- package/skills/service-omni-channel-setup-coordinate/scripts/integration-driver.sh +5 -55
- package/skills/service-omni-channel-setup-coordinate/scripts/tests/test_omni_contracts.py +0 -38
- package/skills/service-omni-command-center-analyze/SKILL.md +2 -3
- package/skills/service-omni-command-center-analyze/scripts/analyze.sh +3 -3
- package/skills/tableau-next-asset-create/README.md +65 -0
- package/skills/tableau-next-asset-create/SKILL.md +409 -0
- package/skills/tableau-next-asset-create/references/admin-users.md +149 -0
- package/skills/tableau-next-asset-create/references/ai-readiness.md +355 -0
- package/skills/tableau-next-asset-create/references/alerts.md +111 -0
- package/skills/tableau-next-asset-create/references/build-workflow.md +819 -0
- package/skills/tableau-next-asset-create/references/dashboard-authoring.md +302 -0
- package/skills/tableau-next-asset-create/references/dashboard-design-principles.md +352 -0
- package/skills/tableau-next-asset-create/references/data-transform-gotchas.md +210 -0
- package/skills/tableau-next-asset-create/references/data-understanding.md +387 -0
- package/skills/tableau-next-asset-create/references/deep-reference-index.md +74 -0
- package/skills/tableau-next-asset-create/references/destructive-operations.md +62 -0
- package/skills/tableau-next-asset-create/references/edit-dashboard.md +273 -0
- package/skills/tableau-next-asset-create/references/edit-visualization.md +529 -0
- package/skills/tableau-next-asset-create/references/empty-source-handling.md +104 -0
- package/skills/tableau-next-asset-create/references/ingest-and-metric-gotchas.md +638 -0
- package/skills/tableau-next-asset-create/references/insight-bundle.md +69 -0
- package/skills/tableau-next-asset-create/references/large-flat-file-handling.md +331 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/_envelope.json +54 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/_shared-widget-fields.json +122 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/add_page.json +29 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/delete_page.json +27 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/discard_dashboard.json +11 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/move_widget.json +30 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/move_widget_to_page.json +30 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/place_widget_on_page.json +30 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/remove_widget_from_dashboard.json +16 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/remove_widget_from_page.json +26 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/rename_page.json +28 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/save_dashboard.json +18 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/undo.json +11 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_button_widget.json +69 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_container_widget.json +88 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_filter_widget.json +146 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_metric_widget.json +78 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_navigation_widget.json +80 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_parameter_widget.json +160 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_text_widget.json +103 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_visualization_widget.json +68 -0
- package/skills/tableau-next-asset-create/references/sdm-tool-reference.md +721 -0
- package/skills/tableau-next-asset-create/references/semantic-query-and-enrichment.md +355 -0
- package/skills/tableau-next-asset-create/references/shared-gates.md +322 -0
- package/skills/tableau-next-asset-create/references/sharing-and-promotion.md +306 -0
- package/skills/tableau-next-asset-create/references/tasks/ai-readiness-audit.md +51 -0
- package/skills/tableau-next-asset-create/references/tasks/analyze-data.md +48 -0
- package/skills/tableau-next-asset-create/references/tasks/build-dashboard.md +66 -0
- package/skills/tableau-next-asset-create/references/tasks/build-end-to-end.md +73 -0
- package/skills/tableau-next-asset-create/references/tasks/create-data-transform.md +51 -0
- package/skills/tableau-next-asset-create/references/tasks/create-viz.md +58 -0
- package/skills/tableau-next-asset-create/references/tasks/edit-dashboard.md +80 -0
- package/skills/tableau-next-asset-create/references/tasks/edit-sdm.md +106 -0
- package/skills/tableau-next-asset-create/references/tasks/edit-viz.md +40 -0
- package/skills/tableau-next-asset-create/references/tasks/enrich-model.md +68 -0
- package/skills/tableau-next-asset-create/references/tasks/ingest-flat-file.md +68 -0
- package/skills/tableau-next-asset-create/references/tasks/manage-alert.md +35 -0
- package/skills/tableau-next-asset-create/references/tasks/profile-dataset.md +47 -0
- package/skills/tableau-next-asset-create/references/tasks/promote-or-reuse.md +46 -0
- package/skills/tableau-next-asset-create/references/tasks/provision-user.md +39 -0
- package/skills/tableau-next-asset-create/references/tasks/query-model.md +92 -0
- package/skills/tableau-next-asset-create/references/tasks/review-verified-questions.md +42 -0
- package/skills/tableau-next-asset-create/references/tasks/share-asset.md +37 -0
- package/skills/tableau-next-asset-create/references/verified-questions.md +125 -0
- package/skills/tableau-next-asset-create/references/viz-authoring.md +992 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-dangling-refs.sh +0 -42
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-hosting-target.sh +0 -26
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-1-complete.sh +0 -35
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-4-complete.sh +0 -47
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-6-ready.sh +0 -33
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-prerequisites.sh +0 -20
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-sfdx-project.sh +0 -15
- package/skills/experience-ui-bundle-custom-app-generate/scripts/resolve-uibundle-path.sh +0 -30
- package/skills/experience-ui-bundle-frontend-generate/scripts/check-preconditions.sh +0 -37
- package/skills/experience-ui-bundle-frontend-generate/scripts/resolve-ui-bundle.sh +0 -66
- package/skills/experience-ui-bundle-frontend-generate/scripts/verify-rules.sh +0 -58
- package/skills/experience-ui-bundle-metadata-generate/scripts/check-api-version.sh +0 -30
- package/skills/experience-ui-bundle-metadata-generate/scripts/detect-framework.sh +0 -73
- package/skills/experience-ui-bundle-metadata-generate/scripts/verify-bundle-location.sh +0 -118
- package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/predefined-incident-policy.json +0 -102
|
@@ -64,18 +64,27 @@ class ParseTests(unittest.TestCase):
|
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
class ResolveOrgTests(unittest.TestCase):
|
|
67
|
-
"""Tests for
|
|
67
|
+
"""Tests for fail-fast access-token retrieval per forcedotcom/cli#3560.
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
The token comes ONLY from ``sf org auth show-access-token --json
|
|
70
|
+
--no-prompt``; ``sf org display`` supplies instanceUrl only. The
|
|
71
|
+
display stub deliberately carries a non-empty ``TOKEN_FROM_DISPLAY``
|
|
72
|
+
so any regression to a display-token fallback is caught.
|
|
71
73
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
full-failure paths without spawning real processes.
|
|
74
|
+
Tests mock ``subprocess.run`` with a side-effect callable that routes
|
|
75
|
+
by argv shape (preflight ``--help`` / display / show-access-token)
|
|
76
|
+
without spawning real processes.
|
|
76
77
|
"""
|
|
77
78
|
|
|
78
79
|
REDACTED_TOKEN = "[REDACTED] Use 'sf org auth show-access-token' to view"
|
|
80
|
+
PREFLIGHT_ARGV = ["sf", "org", "auth", "show-access-token", "--help"]
|
|
81
|
+
# Shape of real ``--help`` output (sf CLI 2.150.6).
|
|
82
|
+
REAL_HELP = "USAGE\n $ sf org auth show-access-token -o <value> [--json]\n"
|
|
83
|
+
|
|
84
|
+
def setUp(self):
|
|
85
|
+
# The preflight caches success process-wide; isolate every test.
|
|
86
|
+
dc._show_access_token_capability_ok = False
|
|
87
|
+
self.addCleanup(setattr, dc, "_show_access_token_capability_ok", False)
|
|
79
88
|
|
|
80
89
|
def _cp(self, stdout: str, *, returncode: int = 0, stderr: str = ""):
|
|
81
90
|
return SimpleNamespace(
|
|
@@ -91,36 +100,38 @@ class ResolveOrgTests(unittest.TestCase):
|
|
|
91
100
|
def _show_token_payload(self, *, access_token: str = "TOKEN_FROM_SHOW") -> str:
|
|
92
101
|
return json.dumps({"result": {"accessToken": access_token}})
|
|
93
102
|
|
|
94
|
-
def _route(self,
|
|
95
|
-
|
|
103
|
+
def _route(self, *, preflight_missing=False, primary_fails=False,
|
|
104
|
+
primary_token="TOKEN_FROM_SHOW", captured=None):
|
|
96
105
|
"""Build a fake_run that routes by argv shape.
|
|
97
106
|
|
|
98
|
-
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
-
|
|
103
|
-
|
|
107
|
+
- preflight_missing → ``show-access-token --help`` raises
|
|
108
|
+
CalledProcessError (sf CLI lacks the command)
|
|
109
|
+
- primary_fails → token call raises CalledProcessError
|
|
110
|
+
(e.g. org not authenticated)
|
|
111
|
+
- primary_token → accessToken returned by the token call
|
|
112
|
+
- captured → optional list; each (argv, kwargs) is appended
|
|
104
113
|
"""
|
|
105
114
|
def fake_run(argv, **kwargs):
|
|
106
|
-
|
|
115
|
+
if captured is not None:
|
|
116
|
+
captured.append((argv, kwargs))
|
|
117
|
+
if "show-access-token" in argv and "--help" in argv:
|
|
118
|
+
if preflight_missing:
|
|
119
|
+
raise subprocess.CalledProcessError(
|
|
120
|
+
returncode=1, cmd=argv,
|
|
121
|
+
stderr="show-access-token is not a sf command",
|
|
122
|
+
)
|
|
123
|
+
return self._cp(self.REAL_HELP)
|
|
107
124
|
if "display" in argv:
|
|
108
|
-
return self._cp(
|
|
109
|
-
self._display_payload(
|
|
110
|
-
access_token=(self.REDACTED_TOKEN if display_redacted
|
|
111
|
-
else "TOKEN_FROM_DISPLAY"),
|
|
112
|
-
),
|
|
113
|
-
)
|
|
114
|
-
# show-access-token call
|
|
125
|
+
return self._cp(self._display_payload())
|
|
115
126
|
if "show-access-token" in argv:
|
|
116
|
-
if
|
|
127
|
+
if primary_fails:
|
|
117
128
|
raise subprocess.CalledProcessError(
|
|
118
129
|
returncode=1, cmd=argv,
|
|
119
|
-
stderr="
|
|
130
|
+
stderr="NoOrgAuthenticationError",
|
|
120
131
|
)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
132
|
+
return self._cp(
|
|
133
|
+
self._show_token_payload(access_token=primary_token),
|
|
134
|
+
)
|
|
124
135
|
raise AssertionError(f"unexpected argv: {argv}")
|
|
125
136
|
return fake_run
|
|
126
137
|
|
|
@@ -131,40 +142,133 @@ class ResolveOrgTests(unittest.TestCase):
|
|
|
131
142
|
self.assertEqual(url, "https://example.salesforce.com")
|
|
132
143
|
self.assertEqual(token, "TOKEN_FROM_SHOW")
|
|
133
144
|
|
|
134
|
-
def
|
|
135
|
-
"""
|
|
145
|
+
def test_primary_failure_raises_without_display_fallback(self):
|
|
146
|
+
"""Token command failing is terminal — the display payload's
|
|
147
|
+
accessToken must NOT be used as a fallback."""
|
|
136
148
|
with mock.patch.object(
|
|
137
|
-
dc.subprocess, "run",
|
|
138
|
-
side_effect=self._route(primary_unknown=True),
|
|
149
|
+
dc.subprocess, "run", side_effect=self._route(primary_fails=True),
|
|
139
150
|
):
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
151
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
152
|
+
dc.resolve_org("my-org")
|
|
153
|
+
msg = str(ctx.exception)
|
|
154
|
+
self.assertIn("sf org auth show-access-token", msg)
|
|
155
|
+
self.assertNotIn("TOKEN_FROM_DISPLAY", msg)
|
|
156
|
+
|
|
157
|
+
def test_primary_non_json_output_raises(self):
|
|
158
|
+
def fake_run(argv, **kwargs):
|
|
159
|
+
if "--help" in argv:
|
|
160
|
+
return self._cp(self.REAL_HELP)
|
|
161
|
+
if "display" in argv:
|
|
162
|
+
return self._cp(self._display_payload())
|
|
163
|
+
return self._cp("Warning: something not json")
|
|
164
|
+
|
|
165
|
+
with mock.patch.object(dc.subprocess, "run", side_effect=fake_run):
|
|
166
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
167
|
+
dc.resolve_org("my-org")
|
|
168
|
+
self.assertIn("sf org auth show-access-token", str(ctx.exception))
|
|
143
169
|
|
|
144
|
-
def
|
|
145
|
-
"""
|
|
146
|
-
|
|
170
|
+
def test_primary_redacted_raises(self):
|
|
171
|
+
"""Dedicated command returns the placeholder — fail fast rather than
|
|
172
|
+
handing the redaction string to downstream callers (which would
|
|
173
|
+
cause INVALID_AUTH_HEADER 401 on every call)."""
|
|
147
174
|
with mock.patch.object(
|
|
148
175
|
dc.subprocess, "run",
|
|
149
|
-
side_effect=self._route(
|
|
176
|
+
side_effect=self._route(primary_token=self.REDACTED_TOKEN),
|
|
150
177
|
):
|
|
151
|
-
|
|
152
|
-
|
|
178
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
179
|
+
dc.resolve_org("my-org")
|
|
180
|
+
self.assertIn("could not retrieve a usable access token", str(ctx.exception))
|
|
153
181
|
|
|
154
|
-
def
|
|
155
|
-
"""If both paths return the placeholder, surface a clean SystemExit
|
|
156
|
-
rather than handing back the redaction string to downstream callers
|
|
157
|
-
(which would cause INVALID_AUTH_HEADER 401 on every Tooling/REST call)."""
|
|
182
|
+
def test_primary_empty_token_raises(self):
|
|
158
183
|
with mock.patch.object(
|
|
159
|
-
dc.subprocess, "run",
|
|
160
|
-
side_effect=self._route(primary_redacted=True, display_redacted=True),
|
|
184
|
+
dc.subprocess, "run", side_effect=self._route(primary_token=""),
|
|
161
185
|
):
|
|
162
186
|
with self.assertRaises(SystemExit) as ctx:
|
|
163
187
|
dc.resolve_org("my-org")
|
|
164
188
|
self.assertIn("could not retrieve a usable access token", str(ctx.exception))
|
|
165
189
|
|
|
190
|
+
def test_capability_preflight_failure_raises_clear_error(self):
|
|
191
|
+
"""sf CLI without `sf org auth show-access-token` → actionable
|
|
192
|
+
upgrade message, and the token call is never attempted."""
|
|
193
|
+
captured: list = []
|
|
194
|
+
with mock.patch.object(
|
|
195
|
+
dc.subprocess, "run",
|
|
196
|
+
side_effect=self._route(preflight_missing=True, captured=captured),
|
|
197
|
+
):
|
|
198
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
199
|
+
dc.resolve_org("my-org")
|
|
200
|
+
msg = str(ctx.exception)
|
|
201
|
+
self.assertIn("missing required command", msg)
|
|
202
|
+
self.assertIn("sf org auth show-access-token", msg)
|
|
203
|
+
self.assertIn("Upgrade/reinstall Salesforce CLI", msg)
|
|
204
|
+
token_calls = [a for a, _ in captured
|
|
205
|
+
if "show-access-token" in a and "--no-prompt" in a]
|
|
206
|
+
self.assertEqual(token_calls, [])
|
|
207
|
+
|
|
208
|
+
def test_zero_exit_without_help_signature_fails_and_is_not_cached(self):
|
|
209
|
+
"""A CLI that answers an unknown command with exit 0 must NOT be
|
|
210
|
+
treated as capable; the failure is not cached, so the next call
|
|
211
|
+
re-probes."""
|
|
212
|
+
bogus = self._cp(
|
|
213
|
+
"\x1b[1mUSAGE\x1b[22m\n $ sf [COMMAND]\n",
|
|
214
|
+
stderr='{"accessToken":"SECRET_Z"}',
|
|
215
|
+
)
|
|
216
|
+
with mock.patch.object(
|
|
217
|
+
dc.subprocess, "run", side_effect=[bogus, self._cp(self.REAL_HELP)],
|
|
218
|
+
) as run:
|
|
219
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
220
|
+
dc._assert_show_access_token_capability()
|
|
221
|
+
msg = str(ctx.exception)
|
|
222
|
+
self.assertIn("missing required command", msg)
|
|
223
|
+
self.assertNotIn("SECRET_Z", msg)
|
|
224
|
+
self.assertFalse(dc._show_access_token_capability_ok)
|
|
225
|
+
dc._assert_show_access_token_capability()
|
|
226
|
+
self.assertEqual(run.call_count, 2)
|
|
227
|
+
self.assertTrue(dc._show_access_token_capability_ok)
|
|
228
|
+
|
|
229
|
+
def test_zero_exit_without_help_signature_blocks_resolve_org(self):
|
|
230
|
+
captured: list = []
|
|
231
|
+
route = self._route(captured=captured)
|
|
232
|
+
|
|
233
|
+
def fake_run(argv, **kwargs):
|
|
234
|
+
if "--help" in argv:
|
|
235
|
+
captured.append((argv, kwargs))
|
|
236
|
+
return self._cp("")
|
|
237
|
+
return route(argv, **kwargs)
|
|
238
|
+
|
|
239
|
+
with mock.patch.object(dc.subprocess, "run", side_effect=fake_run):
|
|
240
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
241
|
+
dc.resolve_org("my-org")
|
|
242
|
+
self.assertIn("lacked the command signature", str(ctx.exception))
|
|
243
|
+
self.assertEqual([a for a, _ in captured], [self.PREFLIGHT_ARGV])
|
|
244
|
+
|
|
245
|
+
def test_zero_exit_unknown_command_notice_echoing_name_fails(self):
|
|
246
|
+
"""Unknown-command notices contain the bare command name; only the
|
|
247
|
+
USAGE form (`$ sf org auth show-access-token`) may pass."""
|
|
248
|
+
for out in (
|
|
249
|
+
"Error: Command org:auth:show-access-token not found.",
|
|
250
|
+
"Warning: show-access-token is not a sf command.",
|
|
251
|
+
"Did you mean org auth show-access-token? Run sf help for options.",
|
|
252
|
+
):
|
|
253
|
+
with self.subTest(out=out):
|
|
254
|
+
dc._show_access_token_capability_ok = False
|
|
255
|
+
with mock.patch.object(
|
|
256
|
+
dc.subprocess, "run", return_value=self._cp("", stderr=out),
|
|
257
|
+
):
|
|
258
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
259
|
+
dc._assert_show_access_token_capability()
|
|
260
|
+
self.assertIn("missing required command", str(ctx.exception))
|
|
261
|
+
self.assertFalse(dc._show_access_token_capability_ok)
|
|
262
|
+
|
|
263
|
+
def test_real_help_signature_passes_preflight(self):
|
|
264
|
+
with mock.patch.object(
|
|
265
|
+
dc.subprocess, "run", return_value=self._cp(self.REAL_HELP),
|
|
266
|
+
):
|
|
267
|
+
dc._assert_show_access_token_capability()
|
|
268
|
+
self.assertTrue(dc._show_access_token_capability_ok)
|
|
269
|
+
|
|
166
270
|
def test_raises_systemexit_when_sf_cli_missing(self):
|
|
167
|
-
"""sf binary not on PATH — bail with the
|
|
271
|
+
"""sf binary not on PATH — bail with the install hint."""
|
|
168
272
|
with mock.patch.object(
|
|
169
273
|
dc.subprocess, "run", side_effect=FileNotFoundError("sf"),
|
|
170
274
|
):
|
|
@@ -182,49 +286,167 @@ class ResolveOrgTests(unittest.TestCase):
|
|
|
182
286
|
dc.resolve_org("my-org")
|
|
183
287
|
|
|
184
288
|
def test_primary_path_argv_contains_show_access_token(self):
|
|
185
|
-
"""Tripwire —
|
|
289
|
+
"""Tripwire — token call MUST be `sf org auth show-access-token`
|
|
186
290
|
with `--no-prompt`. Without `--no-prompt` the command blocks on a
|
|
187
291
|
confirmation banner that --json doesn't suppress on its own."""
|
|
188
|
-
|
|
292
|
+
captured: list = []
|
|
293
|
+
with mock.patch.object(
|
|
294
|
+
dc.subprocess, "run", side_effect=self._route(captured=captured),
|
|
295
|
+
):
|
|
296
|
+
dc.resolve_org("my-org")
|
|
297
|
+
|
|
298
|
+
argvs = [a for a, _ in captured]
|
|
299
|
+
# display call is still required for non-secret metadata.
|
|
300
|
+
self.assertTrue(any("display" in a for a in argvs))
|
|
301
|
+
primary = next(
|
|
302
|
+
a for a in argvs if "show-access-token" in a and "--no-prompt" in a
|
|
303
|
+
)
|
|
304
|
+
self.assertIn("--json", primary)
|
|
305
|
+
self.assertIn("--target-org", primary)
|
|
306
|
+
|
|
307
|
+
def test_does_not_inject_show_secrets_env(self):
|
|
308
|
+
"""Tripwire: no sf subprocess may rely on SF_TEMP_SHOW_SECRETS
|
|
309
|
+
(removed from sf CLI per forcedotcom/cli#3560)."""
|
|
310
|
+
captured: list = []
|
|
311
|
+
with mock.patch.object(
|
|
312
|
+
dc.subprocess, "run", side_effect=self._route(captured=captured),
|
|
313
|
+
):
|
|
314
|
+
dc.resolve_org("my-org")
|
|
315
|
+
|
|
316
|
+
self.assertTrue(captured)
|
|
317
|
+
for argv, kwargs in captured:
|
|
318
|
+
env = kwargs.get("env") or {}
|
|
319
|
+
self.assertNotIn("SF_TEMP_SHOW_SECRETS", env, msg=argv)
|
|
320
|
+
|
|
321
|
+
def test_preflight_is_first_sf_call(self):
|
|
322
|
+
captured: list = []
|
|
323
|
+
with mock.patch.object(
|
|
324
|
+
dc.subprocess, "run", side_effect=self._route(captured=captured),
|
|
325
|
+
):
|
|
326
|
+
dc.resolve_org("my-org")
|
|
327
|
+
argvs = [a for a, _ in captured]
|
|
328
|
+
self.assertEqual(argvs[0], self.PREFLIGHT_ARGV)
|
|
329
|
+
self.assertIn("display", argvs[1])
|
|
330
|
+
|
|
331
|
+
def test_preflight_failure_never_invokes_display(self):
|
|
332
|
+
captured: list = []
|
|
333
|
+
with mock.patch.object(
|
|
334
|
+
dc.subprocess, "run",
|
|
335
|
+
side_effect=self._route(preflight_missing=True, captured=captured),
|
|
336
|
+
):
|
|
337
|
+
with self.assertRaises(SystemExit):
|
|
338
|
+
dc.resolve_org("my-org")
|
|
339
|
+
self.assertEqual([a for a, _ in captured], [self.PREFLIGHT_ARGV])
|
|
340
|
+
|
|
341
|
+
def test_missing_sf_reports_preflight_error_not_display(self):
|
|
342
|
+
captured: list = []
|
|
189
343
|
|
|
190
344
|
def fake_run(argv, **kwargs):
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
return self._cp(self._display_payload())
|
|
194
|
-
return self._cp(self._show_token_payload())
|
|
345
|
+
captured.append(argv)
|
|
346
|
+
raise FileNotFoundError("sf")
|
|
195
347
|
|
|
196
348
|
with mock.patch.object(dc.subprocess, "run", side_effect=fake_run):
|
|
197
|
-
|
|
349
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
350
|
+
dc.resolve_org("my-org")
|
|
351
|
+
self.assertIn("sf CLI not found", str(ctx.exception))
|
|
352
|
+
self.assertEqual(captured, [self.PREFLIGHT_ARGV])
|
|
198
353
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
354
|
+
def test_preflight_runs_once_across_two_resolves(self):
|
|
355
|
+
captured: list = []
|
|
356
|
+
with mock.patch.object(
|
|
357
|
+
dc.subprocess, "run", side_effect=self._route(captured=captured),
|
|
358
|
+
):
|
|
359
|
+
dc.resolve_org("my-org")
|
|
360
|
+
dc.resolve_org("my-org")
|
|
361
|
+
argvs = [a for a, _ in captured]
|
|
362
|
+
self.assertEqual(argvs.count(self.PREFLIGHT_ARGV), 1)
|
|
363
|
+
self.assertEqual(sum(1 for a in argvs if "display" in a), 2)
|
|
207
364
|
|
|
208
|
-
def
|
|
209
|
-
|
|
210
|
-
with
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
365
|
+
def test_failed_preflight_is_retried_on_next_resolve(self):
|
|
366
|
+
captured: list = []
|
|
367
|
+
with mock.patch.object(
|
|
368
|
+
dc.subprocess, "run",
|
|
369
|
+
side_effect=self._route(preflight_missing=True, captured=captured),
|
|
370
|
+
):
|
|
371
|
+
with self.assertRaises(SystemExit):
|
|
372
|
+
dc.resolve_org("my-org")
|
|
373
|
+
with mock.patch.object(
|
|
374
|
+
dc.subprocess, "run", side_effect=self._route(captured=captured),
|
|
375
|
+
):
|
|
376
|
+
_url, token = dc.resolve_org("my-org")
|
|
377
|
+
self.assertEqual(token, "TOKEN_FROM_SHOW")
|
|
378
|
+
argvs = [a for a, _ in captured]
|
|
379
|
+
self.assertEqual(argvs.count(self.PREFLIGHT_ARGV), 2)
|
|
214
380
|
|
|
381
|
+
def _token_call_fails_with(self, *, stdout: str, stderr: str):
|
|
215
382
|
def fake_run(argv, **kwargs):
|
|
383
|
+
if "--help" in argv:
|
|
384
|
+
return self._cp(self.REAL_HELP)
|
|
216
385
|
if "display" in argv:
|
|
217
|
-
captured["argv"] = argv
|
|
218
|
-
captured["env"] = kwargs.get("env")
|
|
219
386
|
return self._cp(self._display_payload())
|
|
220
|
-
|
|
387
|
+
raise subprocess.CalledProcessError(
|
|
388
|
+
returncode=1, cmd=argv, output=stdout, stderr=stderr,
|
|
389
|
+
)
|
|
390
|
+
return fake_run
|
|
221
391
|
|
|
222
|
-
|
|
392
|
+
def test_token_call_failure_output_is_redacted(self):
|
|
393
|
+
"""A failing `show-access-token --json` can echo the token on
|
|
394
|
+
stdout (or a bearer header on stderr); neither may reach the exit
|
|
395
|
+
message."""
|
|
396
|
+
cases = {
|
|
397
|
+
"stdout_only": ('{"accessToken":"SECRET_X"}', ""),
|
|
398
|
+
"stderr_and_stdout": (
|
|
399
|
+
'{"accessToken":"SECRET_X"}',
|
|
400
|
+
"Error: request failed\nBearer SECRET_Y\n",
|
|
401
|
+
),
|
|
402
|
+
"auth_header_and_qs": (
|
|
403
|
+
"", "Authorization: Bearer SECRET_Y accessToken=SECRET_X",
|
|
404
|
+
),
|
|
405
|
+
}
|
|
406
|
+
for label, (stdout, stderr) in cases.items():
|
|
407
|
+
with self.subTest(label):
|
|
408
|
+
with mock.patch.object(
|
|
409
|
+
dc.subprocess, "run",
|
|
410
|
+
side_effect=self._token_call_fails_with(
|
|
411
|
+
stdout=stdout, stderr=stderr,
|
|
412
|
+
),
|
|
413
|
+
):
|
|
414
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
415
|
+
dc.resolve_org("my-org")
|
|
416
|
+
msg = str(ctx.exception)
|
|
417
|
+
self.assertNotIn("SECRET_X", msg)
|
|
418
|
+
self.assertNotIn("SECRET_Y", msg)
|
|
419
|
+
self.assertIn("<redacted>", msg)
|
|
420
|
+
|
|
421
|
+
def test_preflight_failure_output_is_redacted(self):
|
|
422
|
+
for label, (stdout, stderr) in {
|
|
423
|
+
"stdout_only": ('{"accessToken":"SECRET_X"}', ""),
|
|
424
|
+
"stderr": ("", "Bearer SECRET_Y"),
|
|
425
|
+
}.items():
|
|
426
|
+
with self.subTest(label):
|
|
427
|
+
dc._show_access_token_capability_ok = False
|
|
428
|
+
err = subprocess.CalledProcessError(
|
|
429
|
+
returncode=1, cmd=self.PREFLIGHT_ARGV,
|
|
430
|
+
output=stdout, stderr=stderr,
|
|
431
|
+
)
|
|
432
|
+
with mock.patch.object(dc.subprocess, "run", side_effect=err):
|
|
433
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
434
|
+
dc.resolve_org("my-org")
|
|
435
|
+
msg = str(ctx.exception)
|
|
436
|
+
self.assertIn("missing required command", msg)
|
|
437
|
+
self.assertNotIn("SECRET_X", msg)
|
|
438
|
+
self.assertNotIn("SECRET_Y", msg)
|
|
439
|
+
|
|
440
|
+
def test_display_call_still_passes_verbose(self):
|
|
441
|
+
"""org_display still includes --verbose for metadata shape stability."""
|
|
442
|
+
captured: list = []
|
|
443
|
+
with mock.patch.object(
|
|
444
|
+
dc.subprocess, "run", side_effect=self._route(captured=captured),
|
|
445
|
+
):
|
|
223
446
|
dc.resolve_org("my-org")
|
|
224
447
|
|
|
225
|
-
|
|
226
|
-
self.
|
|
227
|
-
self.assertEqual(captured["env"].get("SF_TEMP_SHOW_SECRETS"), "true")
|
|
448
|
+
display_argv = next(a for a, _ in captured if "display" in a)
|
|
449
|
+
self.assertIn("--verbose", display_argv)
|
|
228
450
|
|
|
229
451
|
|
|
230
452
|
# -----------------------------------------------------------------------------
|