afv-library/skills/sales-agentforce-pipeline-management-configure/references/auth-and-cli.md

6.7 KiB

Authentication and CLI Compatibility

Authentication Methods

ORG="pipeline-mgmt-org"
BROWSER=/usr/bin/open sf org login web --instance-url https://login.salesforce.com --alias $ORG

SFDX Auth URL (CI/CD and Automation)

# Export from authenticated org
sf org display --target-org $ORG --verbose --json 2>/dev/null | jq -r '.result.sfdxAuthUrl' > authurl.txt

# Import in another environment
sf org login sfdx-url --sfdx-url-file authurl.txt --alias $ORG

JWT Bearer (Service Accounts)

sf org login jwt --client-id <connected-app-client-id> \
  --jwt-key-file server.key \
  --username admin@example.com \
  --instance-url https://login.salesforce.com \
  --alias $ORG

Extracting Credentials

# Get instance URL (always works)
INSTANCE_URL=$(sf org display --target-org $ORG --json 2>/dev/null | jq -r '.result.instanceUrl')

# Get access token — newer CLI versions (2.108+) REDACT it in sf org display --json
ACCESS_TOKEN=$(sf org display --target-org $ORG --json 2>/dev/null | jq -r '.result.accessToken')

# Fallback for redacted token (CLI 2.108+)
if [[ -z "$ACCESS_TOKEN" || "$ACCESS_TOKEN" == "null" || "$ACCESS_TOKEN" == *"REDACTED"* ]]; then
  ACCESS_TOKEN=$(echo "y" | sf org auth show-access-token --target-org $ORG --no-prompt --json 2>/dev/null | jq -r '.result.accessToken // empty')
fi

Why the fallback: Starting with SF CLI ~2.108, sf org display --json returns "[REDACTED] Use 'sf org auth show-access-token' to view" instead of the actual token. The sf org auth show-access-token --json command always returns the real token. The echo "y" handles the interactive confirmation prompt in non-TTY environments.

Why 2>/dev/null: The Salesforce CLI emits non-JSON warnings to stderr (plugin updates, deprecation notices). When piping to jq, these warnings get mixed with stdout on some CLI versions, causing parse failures. The 2>/dev/null ensures only clean JSON reaches jq.


CLI Compatibility Notes

Version Requirements

Feature Minimum CLI Version Notes
sf data query Any Core command
sf data create record Any Core command
sf org assign permset v2.20+ Use Data API fallback for older versions
sf org assign permsetgroup v2.130+ Use Data API fallback for older versions
sf project retrieve start v2.0+ Core command
sf project deploy start v2.0+ Core command
sf agent commands v2.50+ Requires @salesforce/plugin-agent; creates Agent Script (AiAuthoringBundle) agents, NOT classic Bots

Permission Assignment Compatibility

# Modern CLI (v2.130+):
sf org assign permsetgroup --name SalesManagementUserPsg --on-behalf-of user@example.com --target-org $ORG --json 2>/dev/null

# Universal fallback (all CLI versions) — Data API approach:
PSG_ID=$(sf data query -q "SELECT Id FROM PermissionSetGroup WHERE DeveloperName = 'SalesManagementUserPsg'" --target-org $ORG --json 2>/dev/null | jq -r '.result.records[0].Id')
USER_ID=$(sf data query -q "SELECT Id FROM User WHERE Username = 'user@example.com'" --target-org $ORG --json 2>/dev/null | jq -r '.result.records[0].Id')
sf data create record --sobject PermissionSetAssignment --values "AssigneeId='${USER_ID}' PermissionSetGroupId='${PSG_ID}'" --target-org $ORG --json 2>/dev/null
# DUPLICATE_VALUE error = already assigned = success

SOAP API vs CLI for Settings (Verified)

Settings that REQUIRE SOAP API (CLI cannot even retrieve them):

  • SalesDealAgentSettings — CLI returns "Settings type is unknown"

Settings that work with CLI (verified — retrieve AND deploy both succeed):

  • EinsteinGptSettings — CLI deploy works, no silent failure observed
  • EinsteinCopilotSettings — CLI deploy works
  • OpportunitySettings — CLI deploy works (may fail on specific fields that require additional config)
  • EnhancedNotesSettings — CLI retrieve works
  • EmailAdministrationSettings — CLI retrieve works

Recommendation: Use SOAP API for SalesDealAgentSettings (only option). For other settings, CLI is acceptable but SOAP provides a uniform approach. Always verify after deployment regardless of method.

CLI Retrieve Returns Empty for Settings (Known Issue)

Symptom: sf project retrieve start --metadata "Settings:EinsteinGptSettings" succeeds but creates empty directories with no XML files, even when the setting is enabled in the org.

Root cause: The CLI retrieve for Settings metadata types has a known limitation where:

  1. The type must be known to the CLI's internal metadata registry
  2. Even known types may return empty if the org has no explicit customization (only default values)
  3. Some settings types (like SalesDealAgentSettings) are not in the registry at all

Workaround — Use SOAP readMetadata for verification:

# Instead of retrieving via CLI, use SOAP readMetadata to CHECK settings state
curl -s "${INSTANCE_URL}/services/Soap/m/64.0" \
  -H "Content-Type: text/xml; charset=UTF-8" \
  -H "SOAPAction: readMetadata" \
  -d "<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:met='http://soap.sforce.com/2006/04/metadata'>
  <soapenv:Header><met:SessionHeader><met:sessionId>${ACCESS_TOKEN}</met:sessionId></met:SessionHeader></soapenv:Header>
  <soapenv:Body><met:readMetadata><met:type>EinsteinGptSettings</met:type><met:fullNames>EinsteinGpt</met:fullNames></met:readMetadata></soapenv:Body>
</soapenv:Envelope>" | grep -o "<enableEinsteinGptPlatform>[^<]*"

Workaround — Use SOAP updateMetadata for deployment:

# For settings that CLI can't deploy, use SOAP updateMetadata
# (see scripts/setup-all.sh for full patterns)

Rule: Never trust sf project retrieve start for Settings verification. Always verify enablement via SOAP readMetadata or direct API queries after any deploy operation.

See references/soap-api-enablement.md for all SOAP API patterns.


CLI Hardening Rules

  1. Always use 2>/dev/null on sf ... --json piped to jq
  2. Always verify enablement after deploy (don't trust success response alone)
  3. Never use sf project deploy start for SalesDealAgentSettings (not recognized by CLI)
  4. Never use --use-tooling-api for BotDefinition queries (not supported — use standard SOQL)
  5. Prefer Data API approach for permission assignments (universal compatibility)
  6. Check jq output for null before using variables (prevents empty-string commands)
# Safe variable extraction pattern
VALUE=$(sf data query -q "..." --target-org $ORG --json 2>/dev/null | jq -r '.result.records[0].Id // empty')
if [[ -z "$VALUE" ]]; then
  echo "ERROR: Query returned no results"
  exit 1
fi