Skip to content

Commit b992529

Browse files
jeffdijdicorpo
andauthored
fix(init): don't require SFTP account for cf init and non-SFTP commands (2.4.1) (#17)
Users without an SFTP account (not yet eligible: no paid/waived/sponsored project or no SSH key on profile) could not run cf init, because the command aborted with "No SFTP account linked to your platform account. Please run 'cf login' first." The SFTP account is only used as a label in .cf/project.json, which the backend stores as an opaque blob and the CLI never reads back, so blocking init on it was incorrect. - cf init: fall back to user_email (or "unknown") for the proj['user'] metadata field; only refresh sftp_username from /auth/cli/whoami when an api_key is present, and never abort. - cf status: SFTP listing becomes a best-effort extra. When no SFTP account is linked, print the platform status, skip SFTP with a soft hint, and exit cleanly. - cf push (SFTP), cf pull, cf tapeouts, cf confirm: keep the SFTP gate but replace the "Contact support" message with one that explains the eligibility path (deposit paid/waived/sponsored + SSH key on profile). - Bump version to 2.4.1 in pyproject.toml and align __init__.py which had drifted at 2.3.2. cf precheck (local), cf precheck --remote, and cf push --remote already worked without SFTP and are unchanged. Made-with: Cursor Co-authored-by: jdicorpo <jdicorpo@gmail.com>
1 parent 21ffa31 commit b992529

3 files changed

Lines changed: 50 additions & 20 deletions

File tree

chipfoundry_cli/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
"""ChipFoundry CLI package: Automate project submission to SFTP."""
2-
__version__ = "2.3.2"
2+
__version__ = "2.4.1"

chipfoundry_cli/main.py

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,13 @@ def init(project_root, shuttle, description):
402402
local_proj = local_data.get('project', {}) if isinstance(local_data, dict) else {}
403403

404404
config = load_user_config()
405+
api_key = config.get('api_key')
405406
username = config.get("sftp_username")
406-
if not username:
407+
# Try to refresh sftp_username from the platform, but don't block init on it.
408+
# SFTP accounts are only auto-provisioned once a project deposit is paid/waived/
409+
# sponsored and the user has an SSH key on their profile; init must work before
410+
# that so users can configure locally and use `cf precheck` / `cf push --remote`.
411+
if not username and api_key:
407412
try:
408413
me = _api_get("/auth/cli/whoami")
409414
username = me.get("sftp_username")
@@ -412,11 +417,10 @@ def init(project_root, shuttle, description):
412417
save_user_config(config)
413418
except SystemExit:
414419
pass
415-
if not username:
416-
console.print("[bold red]No SFTP account linked to your platform account. Please run 'cf login' first.[/bold red]")
417-
raise click.Abort()
418-
419-
api_key = config.get('api_key')
420+
# Fall back to email (or 'unknown') purely as a label in .cf/project.json.
421+
# This field is metadata only: SFTP routing uses the live session identity,
422+
# and the backend stores cli_project_json as an opaque blob.
423+
user_label = username or config.get("user_email") or "unknown"
420424
platform_id = local_proj.get('platform_project_id')
421425
platform_proj: Optional[dict] = None
422426
if platform_id and api_key:
@@ -469,7 +473,7 @@ def _merged(key_local: str, key_platform: Optional[str] = None) -> Optional[str]
469473
proj = data.setdefault('project', {})
470474
proj['name'] = name
471475
proj['type'] = project_type
472-
proj['user'] = username
476+
proj['user'] = user_label
473477
proj.setdefault('version', local_proj.get('version') or "1")
474478
proj.setdefault('user_project_wrapper_hash', local_proj.get('user_project_wrapper_hash', ""))
475479
proj.setdefault('submission_state', local_proj.get('submission_state', "Draft"))
@@ -1619,7 +1623,11 @@ def push(project_root, sftp_host, sftp_username, sftp_key, project_id, project_n
16191623
sftp_username = me.get("sftp_username")
16201624
if not sftp_username:
16211625
console.print("[bold red]No SFTP account linked to your platform account.[/bold red]")
1622-
console.print("Contact support or provide --sftp-username.")
1626+
console.print(
1627+
"An SFTP account is provisioned once a project deposit is paid/waived/sponsored "
1628+
"and an SSH public key is on your profile."
1629+
)
1630+
console.print("Override with --sftp-username if you already know yours, or contact support.")
16231631
raise click.Abort()
16241632
config["sftp_username"] = sftp_username
16251633
save_user_config(config)
@@ -1805,7 +1813,11 @@ def pull(project_name, output_dir, sftp_host, sftp_username, sftp_key):
18051813
sftp_username = me.get("sftp_username")
18061814
if not sftp_username:
18071815
console.print("[bold red]No SFTP account linked to your platform account.[/bold red]")
1808-
console.print("Contact support or provide --sftp-username.")
1816+
console.print(
1817+
"An SFTP account is provisioned once a project deposit is paid/waived/sponsored "
1818+
"and an SSH public key is on your profile."
1819+
)
1820+
console.print("Override with --sftp-username if you already know yours, or contact support.")
18091821
raise click.Abort()
18101822
config["sftp_username"] = sftp_username
18111823
save_user_config(config)
@@ -2089,24 +2101,34 @@ def status(sftp_host, sftp_username, sftp_key, json_output, show_all):
20892101
platform_id = _load_project_platform_id(os.getcwd())
20902102
if not platform_id:
20912103
console.print("[dim]Tip: Run [bold]cf link[/bold] to connect this project to the platform.[/dim]\n")
2104+
# SFTP listing is a best-effort extra on top of the platform status above.
2105+
# Skip it quietly when the user has no SFTP account yet (auto-provisioned
2106+
# after a project deposit is paid/waived/sponsored + an SSH key is on file).
20922107
if not sftp_username:
2093-
me = _api_get("/auth/cli/whoami")
2094-
sftp_username = me.get("sftp_username")
2108+
if config.get("api_key"):
2109+
try:
2110+
me = _api_get("/auth/cli/whoami")
2111+
sftp_username = me.get("sftp_username")
2112+
except SystemExit:
2113+
sftp_username = None
20952114
if not sftp_username:
2096-
console.print("[red]No SFTP account linked to your platform account.[/red]")
2097-
console.print("Contact support or provide --sftp-username.")
2098-
raise click.Abort()
2115+
console.print(
2116+
"[dim]SFTP listing skipped — no SFTP account linked yet. "
2117+
"An account is provisioned once a project deposit is paid/waived/sponsored "
2118+
"and an SSH public key is on your profile.[/dim]"
2119+
)
2120+
return
20992121
config["sftp_username"] = sftp_username
21002122
save_user_config(config)
21012123
if not sftp_key:
21022124
sftp_key = config.get("sftp_key")
2103-
2125+
21042126
# Always resolve key_path to absolute path if set
21052127
if sftp_key:
21062128
key_path = os.path.abspath(os.path.expanduser(sftp_key))
21072129
else:
21082130
key_path = DEFAULT_SSH_KEY
2109-
2131+
21102132
if not os.path.exists(key_path):
21112133
console.print(f"[red]SFTP key file not found: {key_path}[/red]")
21122134
console.print("[yellow]Please run 'cf keygen' to generate a key or 'cf config' to set a custom key path.[/yellow]")
@@ -2232,7 +2254,11 @@ def tapeouts(sftp_host, sftp_username, sftp_key, limit, days):
22322254
sftp_username = me.get("sftp_username")
22332255
if not sftp_username:
22342256
console.print("[red]No SFTP account linked to your platform account.[/red]")
2235-
console.print("Contact support or provide --sftp-username.")
2257+
console.print(
2258+
"An SFTP account is provisioned once a project deposit is paid/waived/sponsored "
2259+
"and an SSH public key is on your profile."
2260+
)
2261+
console.print("Override with --sftp-username if you already know yours, or contact support.")
22362262
raise click.Abort()
22372263
config["sftp_username"] = sftp_username
22382264
save_user_config(config)
@@ -2422,7 +2448,11 @@ def confirm(project_root, sftp_host, sftp_username, sftp_key, project_name):
24222448
sftp_username = me.get("sftp_username")
24232449
if not sftp_username:
24242450
console.print("[bold red]No SFTP account linked to your platform account.[/bold red]")
2425-
console.print("Contact support or provide --sftp-username.")
2451+
console.print(
2452+
"An SFTP account is provisioned once a project deposit is paid/waived/sponsored "
2453+
"and an SSH public key is on your profile."
2454+
)
2455+
console.print("Override with --sftp-username if you already know yours, or contact support.")
24262456
raise click.Abort()
24272457
config["sftp_username"] = sftp_username
24282458
save_user_config(config)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "chipfoundry-cli"
3-
version = "2.4.0"
3+
version = "2.4.1"
44
description = "CLI tool to automate ChipFoundry project submission to SFTP server"
55
authors = ["ChipFoundry <marwan.abbas@chipfoundry.io>"]
66
readme = "README.md"

0 commit comments

Comments
 (0)