Skip to content

Commit cb45864

Browse files
authored
Merge pull request #111 from forcedotcom/sf-cli-auth-fix-2
Support older versions of SF CLI for deploy command
2 parents 87f5b73 + 30910d9 commit cb45864

3 files changed

Lines changed: 61 additions & 20 deletions

File tree

src/datacustomcode/token_provider.py

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -140,37 +140,44 @@ def _run_sf_command(args: list[str], description: str) -> dict:
140140
)
141141
return dict(data)
142142

143-
# Get instanceUrl from sf org display
143+
# Get org info from sf org display
144144
display_data = _run_sf_command(
145145
["sf", "org", "display", "--target-org", self.sf_cli_org, "--json"],
146146
"sf org display",
147147
)
148-
instance_url = display_data.get("result", {}).get("instanceUrl")
148+
result_data = display_data.get("result", {})
149+
instance_url = result_data.get("instanceUrl")
149150
if not instance_url:
150151
raise RuntimeError(
151152
f"'sf org display' did not return an instance URL "
152153
f"for org '{self.sf_cli_org}'"
153154
)
154155

155-
# Get access token via show-access-token (newer SF CLI versions
156-
# redact the token in sf org display)
157-
token_data = _run_sf_command(
158-
[
159-
"sf",
160-
"org",
161-
"auth",
162-
"show-access-token",
163-
"--target-org",
164-
self.sf_cli_org,
165-
"--json",
166-
],
167-
"sf org auth show-access-token",
168-
)
169-
access_token = token_data.get("result", {}).get("accessToken")
156+
# Try show-access-token first (SF CLI >= 2.136.6); fall back to the
157+
# token from sf org display (older CLIs don't redact it).
158+
access_token = None
159+
try:
160+
token_data = _run_sf_command(
161+
[
162+
"sf",
163+
"org",
164+
"auth",
165+
"show-access-token",
166+
"--target-org",
167+
self.sf_cli_org,
168+
"--json",
169+
],
170+
"sf org auth show-access-token",
171+
)
172+
access_token = token_data.get("result", {}).get("accessToken")
173+
except RuntimeError:
174+
# Command not available on older SF CLI versions
175+
access_token = result_data.get("accessToken")
176+
170177
if not access_token:
171178
raise RuntimeError(
172-
f"'sf org auth show-access-token' did not return an access token "
173-
f"for org '{self.sf_cli_org}'"
179+
f"Could not obtain an access token for org '{self.sf_cli_org}'. "
180+
f"Upgrade SF CLI to 2.136.6+ or ensure the org is authenticated."
174181
)
175182

176183
return AccessTokenResponse(access_token=access_token, instance_url=instance_url)

tests/io/reader/test_sf_cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ def test_missing_access_token_raises_runtime_error(self, reader):
175175
token_result = MagicMock()
176176
token_result.stdout = json.dumps({"status": 0, "result": {}})
177177
with patch("subprocess.run", side_effect=[display_result, token_result]):
178-
with pytest.raises(RuntimeError, match="did not return an access token"):
178+
with pytest.raises(RuntimeError, match="Could not obtain an access token"):
179179
reader._get_token()
180180

181181
def test_missing_instance_url_raises_runtime_error(self, reader):

tests/test_token_provider.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,40 @@ def test_successful_token_retrieval(self):
197197
assert "org" in display_call[0][0] and "display" in display_call[0][0]
198198
assert "show-access-token" in token_call[0][0]
199199

200+
def test_fallback_to_display_token_on_older_cli(self):
201+
"""Test fallback to sf org display token when show-access-token unavailable."""
202+
import json
203+
import subprocess
204+
205+
provider = SFCLITokenProvider("test_org")
206+
207+
display_output = json.dumps(
208+
{
209+
"status": 0,
210+
"result": {
211+
"accessToken": "display_token",
212+
"instanceUrl": "https://cli.salesforce.com",
213+
},
214+
}
215+
)
216+
217+
def side_effect(*args, **kwargs):
218+
cmd = args[0]
219+
if "show-access-token" in cmd:
220+
raise subprocess.CalledProcessError(
221+
returncode=2, cmd="sf", stderr="not a sf command"
222+
)
223+
mock = MagicMock()
224+
mock.stdout = display_output
225+
return mock
226+
227+
with patch("subprocess.run", side_effect=side_effect):
228+
result = provider.get_token()
229+
230+
assert isinstance(result, AccessTokenResponse)
231+
assert result.access_token == "display_token"
232+
assert result.instance_url == "https://cli.salesforce.com"
233+
200234
def test_sf_command_not_found(self):
201235
"""Test that FileNotFoundError is wrapped in RuntimeError."""
202236
provider = SFCLITokenProvider("test_org")

0 commit comments

Comments
 (0)