Skip to content

feat(cli): create keys by permission preset - #1178

Closed
dazip wants to merge 3 commits into
mainfrom
prod-3005-v2-key-creation-via-fal-cli-preset-flags-interactive
Closed

dazip wants to merge 3 commits into
mainfrom
prod-3005-v2-key-creation-via-fal-cli-preset-flags-interactive

Conversation

@dazip

@dazip dazip commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

fal keys create requires --scope ADMIN|API, a binary choice that cannot express anything narrower. This moves the CLI to named permission presets.

fal keys create now takes --preset FULL|API and accepts --alias alongside --desc. With neither --preset nor the now-deprecated --scope, it prompts for a preset in a TTY; a non-interactive run has to pass a flag. Presets map onto the existing scope field — FULL to ADMIN, API to API — so the wire format is unchanged and this stands alone.

Presets with no scope equivalent, and custom permission lists, need a wire field and follow in #1179 and #1180.


Note

Medium Risk
Changes how API keys are created in the CLI (permission selection and interactive defaults); wire format is unchanged but mis-specified presets or CI scripts missing flags could behave differently than before.

Overview
fal keys create now centers on permission presets (FULL / API) instead of requiring --scope. Users can pass --preset, keep --scope as a deprecated alias (mapped via KeyPreset.from_scope), or pick a preset from an interactive Rich table when running in a TTY; non-interactive runs must pass --preset or --scope. --alias is added as a synonym for --desc, and success output refers to the preset name.

A new KeyPreset enum in the SDK defines preset ↔ KeyScope mapping (FULL → ADMIN, API → API) so key creation still uses the existing scope wire field unchanged.

Unit tests cover --preset/--alias parsing, rejecting --preset and --scope together, and the preset/scope mapping helpers.

Reviewed by Cursor Bugbot for commit c025ddf. Bugbot is set up for automated code reviews on this repo. Configure here.

@dazip
dazip marked this pull request as ready for review September 18, 2026 20:12
@dazip dazip changed the title PROD-3005: v2 key creation via fal CLI (preset flags + interactive) feat(cli): create keys by permission preset Sep 18, 2026

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good — a well-contained CLI refactor with correct enum mapping and no security-sensitive surface. Checked: args.console is always set before dispatch (fal/cli/main.py:80), so _prompt_preset referencing it is safe; KeyScope only has ADMIN/API members, so KeyPreset.from_scope's mapping is exhaustive; the interactive-prompt guard raises ValueError (rather than hanging) whenever sys.stdin.isatty() is false, matching the same isatty-mocking pattern already used for interactive prompts in test_deploy.py; and the new --preset/--scope mutual exclusivity plus preset/scope round-trip mapping are covered by the added unit tests.

Extended reasoning...

Overview

The PR adds a KeyPreset enum (FULL/API) in projects/fal/src/fal/sdk.py that maps to/from the existing KeyScope enum, and reworks fal keys create in projects/fal/src/fal/cli/keys.py to accept an optional --preset (mutually exclusive with the now-optional, deprecated --scope), an --alias alias for --desc, and an interactive preset picker (_prompt_preset) when neither flag is supplied. Tests were added covering flag parsing, mutual exclusivity, and the preset/scope mapping functions.

Security risks

None identified. No new external input handling beyond argparse choices, no crypto/auth logic changes (the actual key material generation is unchanged server-side), and the preset-to-scope mapping is a straightforward, exhaustive translation since KeyScope only has two members (ADMIN, API).

Level of scrutiny

This is a small, mechanical, additive CLI change (new optional flag plus an interactive fallback) that preserves backward compatibility with --scope. I verified the two candidate issues surfaced by the bug hunter and found both were already handled by the code: (1) the interactive prompt cannot hang non-interactive callers because it explicitly checks sys.stdin.isatty() and args.console.is_terminal and raises ValueError immediately if not a TTY, rather than blocking on Prompt.ask; (2) the same isatty-mocking approach used elsewhere in this codebase's test suite (test_deploy.py) would work to drive/test this new prompt, so it isn't uniquely untestable, even though a dedicated unit test for the interactive branch wasn't added in this PR.

Other factors

Test coverage for the new non-interactive paths (preset flag, alias, mutual exclusivity, scope/preset mapping) is present and passes review by inspection. The interactive prompt path itself has no direct unit test, which is a minor gap but not a correctness bug, and consistent with the "obvious/mechanical, no ambiguity" bar for approval.

dazip and others added 2 commits September 18, 2026 14:02
fal keys create takes --preset FULL|API, accepts --alias alongside
--desc, and prompts for a preset when neither --preset nor the now
deprecated --scope is given. Presets map onto the existing scope field,
so the wire format is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Also raise a ValueError for the non-interactive preset prompt instead of
SystemExit, so the message goes through the CLI's own error handling.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dazip
dazip force-pushed the prod-3005-v2-key-creation-via-fal-cli-preset-flags-interactive branch from b4c934d to 67b52c1 Compare September 18, 2026 21:04
@fal-ai fal-ai deleted a comment from linear-code Bot Sep 18, 2026
@jim-fal

jim-fal commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

I think internally we're using policy_preset but exposing "preset" terminology externally is not super natural. WDYT about --access full|api ?

"policy" is an internal term and should not surface to users; a preset
is a named permission bundle. Also fixes the long-standing "privilage"
typo on the --scope help line.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dazip

dazip commented Sep 21, 2026

Copy link
Copy Markdown
Contributor Author

Going to stick with --preset — it's the term across the public surfaces now: the web-app creation flow (Permissions section → Preset vs. Custom), the Platform API contract (preset / permissions fields, web-app#8075), and here. access reads as the reach side (what you can hit), while this flag selects a named permission bundle — the rule side — so preset maps more precisely. In practice it shorthands the same way scope did ("FULL preset key" vs. "ADMIN scoped key"). Internal contracts keep policy_preset; the rename happens at the public boundary.

@dazip

dazip commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #1185, which combines all three layers into a single PR so the CLI features ship in one release. The work from this PR is carried over there unchanged apart from the preset no longer being sent on the deprecated scope field.

@dazip dazip closed this Sep 22, 2026
@dazip
dazip deleted the prod-3005-v2-key-creation-via-fal-cli-preset-flags-interactive branch September 22, 2026 17:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants