Commit Graph

10327 Commits

Author SHA1 Message Date
GareArc
fe9412af5d
feat(api): lift POST /oauth/device/code to /openapi/v1 (Phase B.6)
Canonical class OAuthDeviceCodeApi now lives in
controllers/openapi/oauth_device/code.py and is registered on
openapi_ns at /openapi/v1/oauth/device/code. service_api/oauth.py
re-registers the same class object on service_api_ns at
/v1/oauth/device/code so existing callers keep working until Phase F.

KNOWN_CLIENT_IDS literal moves to dify_config.OPENAPI_KNOWN_CLIENT_IDS
(CSV-parsed, default "difyctl") so new CLIs / SDKs can be admitted
without code changes (CLAUDE.md rule 8 — no magic strings).

_verification_uri helper moves with the handler. Single source of
truth — no duplicated logic between the two mounts.

Plan: docs/superpowers/plans/2026-04-26-openapi-migration.md (in difyctl repo).
2026-04-26 23:40:58 -07:00
GareArc
218ef6a447
feat(api): CORS posture for /openapi/v1 (Phase A.5)
OPENAPI_CORS_ALLOW_ORIGINS env var defaults to empty (same-origin only).
Operators expand for third-party integrations via comma-separated list.
Allowed headers: Authorization, Content-Type, X-CSRF-Token. Methods:
GET POST PATCH DELETE OPTIONS. Max-Age 600s. supports_credentials=True
so cookie-authed approve/deny work once Phase D moves them in.

Disallowed origins receive a normal 200 OPTIONS response without the
Access-Control-Allow-Origin header — flask-cors's standard behavior;
browser blocks the cross-origin request from the disallowed origin.

Plan: docs/superpowers/plans/2026-04-26-openapi-migration.md (in difyctl repo).
2026-04-26 23:30:27 -07:00
GareArc
501c0b8746
feat(api): add require_scope decorator (Phase A.4)
Route-level scope gate; pairs with validate_bearer. Bearer holding the
catch-all SCOPE_FULL ('full', carried by dfoa_) passes any check;
narrower bearers (dfoe_, future PATs) need the exact scope listed in
the route decorator.

No v1.0 route applies it yet — apps/datasets controllers will be the
first consumers when those plans land. Programming-error guard: if
@require_scope runs without @validate_bearer above it, raises
RuntimeError instead of silently allowing.

Plan: docs/superpowers/plans/2026-04-26-openapi-migration.md (in difyctl repo).
2026-04-26 23:27:48 -07:00
GareArc
4214583ae5
refactor(api): hoist bearer_feature_required to libs/oauth_bearer (Phase A.3)
The decorator was defined inline in console/auth/oauth_device.py. Phase
D will move approve/deny to controllers/openapi/oauth_device/ and the
new SSO branch under the same group needs the same gate. Hoist it to
libs/oauth_bearer.py now so the move stays a pure file rename later.

Behavior unchanged: 503 'bearer_auth_disabled' when ENABLE_OAUTH_BEARER
is off. console/auth/oauth_device.py imports it from libs and drops
the now-unused dify_config / wraps / ServiceUnavailable imports.

Plan: docs/superpowers/plans/2026-04-26-openapi-migration.md (in difyctl repo).
2026-04-26 23:26:13 -07:00
GareArc
73771cb58c
refactor(api): drop vestigial Accepts.APP from validate_bearer (Phase A.2)
Accepts.APP and the matching app- short-circuit existed to let routes
declare "I accept either OAuth or app- tokens", but no production
caller ever did, and the short-circuit returned without doing the
tenant/app/end-user setup that app- tokens actually need (that lives
in service_api/wraps.py:validate_app_token).

After this change, validate_bearer is OAuth-only. app- bearers fall
through the prefix dispatch and surface as InvalidBearer -> 401, which
is what we already promised on /openapi/* (no app- accepted) and what
the docstring claimed all along.

Pre-check rg "Accepts\\.APP" returned zero hits outside the function
being edited; no callers to update.

Plan: docs/superpowers/plans/2026-04-26-openapi-migration.md (in difyctl repo).
2026-04-26 23:24:56 -07:00
GareArc
f5f224f49d
feat(api): scaffold /openapi/v1 blueprint (Phase A.1)
New Flask blueprint at /openapi/v1/ that will host user-scoped
programmatic endpoints (device flow, identity, sessions, workspaces).
Ships only a smoke route GET /openapi/v1/_health for now; subsequent
phases lift handlers in from service_api, console, and the orphan
oauth_device_sso.py.

CORS is intentionally omitted here and configured in step A.5 once
the allowlist envvar lands.

Plan: docs/superpowers/plans/2026-04-26-openapi-migration.md (in difyctl repo).
2026-04-26 23:08:15 -07:00
GareArc
813da349ec
fix(api,web): post-review hardening for OAuth device flow
- api: account-flow stores subject_issuer="dify:account" sentinel
  instead of NULL so the rotate-in-place unique index collides as
  intended (Postgres treats NULLs as distinct in unique indices).
  mint_oauth_token validates prefix-specific issuer rules.
- api: enterprise_only inverts to an allowlist (ACTIVE / EXPIRING) so
  any future LicenseStatus value defaults to denial.
- api: consume_on_poll moved to a single Lua script (GET + status-check
  + DEL) so concurrent pollers can't both observe APPROVED.
- web: typed DeviceFlowError + central error-copy mapping; page
  surfaces rate_limited / lookup_failed view states; URL params
  scrubbed after consumption (RFC 8628 §5.4).
2026-04-26 23:05:07 -07:00
GareArc
fe8510ad1a
feat(api,web): OAuth 2.0 device flow + bearer auth (RFC 8628)
Adds a CLI-friendly authorization flow so difyctl (and future
non-browser clients) can obtain user-scoped tokens without copy-
pasting cookies or raw API keys. Two grant paths share one device
flow surface:

  1. Account branch — user signs in via the existing /signin
     methods, /device page calls console-authed approve, mints a
     dfoa_ token tied to (account_id, tenant).
  2. External-SSO branch (EE) — /v1/oauth/device/sso-initiate signs
     an SSOState envelope, hands off to Enterprise's external ACS,
     receives a signed external-subject assertion, mints a dfoe_
     token tied to (subject_email, subject_issuer).

API surface (all under /v1, EE-only endpoints 404 on CE):

  POST   /v1/oauth/device/code              — RFC 8628 start
  POST   /v1/oauth/device/token             — RFC 8628 poll
  GET    /v1/oauth/device/lookup            — pre-validate user_code
  GET    /v1/oauth/device/sso-initiate      — SSO branch entry
  GET    /v1/device/sso-complete            — SSO callback sink
  GET    /v1/oauth/device/approval-context  — /device cookie probe
  POST   /v1/oauth/device/approve-external  — SSO approve
  GET    /v1/me                             — bearer subject lookup
  DELETE /v1/oauth/authorizations/self      — self-revoke
  POST   /console/api/oauth/device/approve  — account approve
  POST   /console/api/oauth/device/deny     — account deny

Core primitives:
- libs/oauth_bearer.py: prefix-keyed TokenKindRegistry +
  BearerAuthenticator + validate_bearer decorator. Two-tier scope
  (full vs apps:run) stamped from the registry, never from the DB.
- libs/jws.py: HS256 compact JWS keyed on the shared Dify
  SECRET_KEY — same key-set verifies the SSOState envelope, the
  external-subject assertion (minted by Enterprise), and the
  approval-grant cookie.
- libs/device_flow_security.py: enterprise_only gate, approval-
  grant cookie mint/verify/consume (Path=/v1/oauth/device,
  HttpOnly, SameSite=Lax, Secure follows is_secure()), anti-
  framing headers.
- libs/rate_limit.py: typed RateLimit / RateLimitScope dispatch
  with composite-key buckets; both decorator + imperative form.
- services/oauth_device_flow.py: Redis state machine (PENDING ->
  APPROVED|DENIED with atomic consume-on-poll), token mint via
  partial unique index uq_oauth_active_per_device (rotates in
  place), env-driven TTL policy.

Storage: oauth_access_tokens table with partial unique index on
(subject_email, subject_issuer, client_id, device_label) WHERE
revoked_at IS NULL. account_id NULL distinguishes external-SSO
rows. Hard-expire is CAS UPDATE (revoked_at + nullify token_hash)
so audit events keep their token_id. Retention pruner DELETEs
revoked + zombie-expired rows past OAUTH_ACCESS_TOKEN_RETENTION_DAYS.

Frontend: /device page with code-entry, chooser (account vs SSO),
authorize-account, authorize-sso views. SSO branch detaches from
the URL user_code and reads everything from the cookie via
/approval-context. Anti-framing headers on all responses.

Wiring: ENABLE_OAUTH_BEARER feature flag; ext_oauth_bearer binds
the authenticator at startup; clean_oauth_access_tokens_task
scheduled in ext_celery.

Spec: docs/specs/v1.0/server/{device-flow,tokens,middleware,security}.md
2026-04-26 20:06:43 -07:00
BitCompass
8f070f2190
refactor(api): flatten nested conditionals and clean up token helpers (#34835) 2026-04-20 03:39:54 +00:00
yyh
c7641bb1ce
refactor(web): unify app-shell bootstrap on TanStack Query + Next.js route conventions (#35394)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-20 02:52:08 +00:00
dev-miro26
97bb338e7d
fix: prevent double /v1 in MCP server URL causing 404 authorization failure (#34596)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-20 02:42:59 +00:00
hyl64
ceec00e172
fix: accept icon type in app icon updates (#35360)
Co-authored-by: Stephen Zhou <hi@hyoban.cc>
2026-04-20 02:33:49 +00:00
非法操作
d81444683b
chore: improve conversation opener (#35403)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-20 02:33:04 +00:00
非法操作
3627c1e720
refactor: remove file upload migration tip (#35409) 2026-04-20 02:29:30 +00:00
非法操作
ba5d8c1b29
fix: complete assigned variable reference descriptions (#35406) 2026-04-20 02:09:05 +00:00
Jean Ibarz
26e50bb084
refactor(web): convert file-local Step enum to as-const in website crawlers 🤖🤖🤖 (#34565)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-20 01:41:32 +00:00
yyh
b351ab00a2
fix(web): prevent infinite render loop on /apps page (#35393) 2026-04-20 00:41:01 +00:00
Asuka Minato
059d605a6d
ci: Update pyrefly dependency version to 0.61.1 (#35391)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-19 15:49:24 +00:00
Asuka Minato
f8a4205ac4
chore: Replace 'db' with 'sa' for SQLAlchemy compatibility (#35373)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-19 09:56:19 +00:00
yyh
25dd79fba7
fix(web): remove dynamic import from Goto Anything to restore cmd+k (#35383) 2026-04-18 13:33:13 +00:00
yyh
0c8acd402a
chore(web): drop delay={0} from tooltip triggers and retype DocName (#35382)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-18 11:21:07 +00:00
99
3e876e173a
chore(api): adapt Graphon 0.2.2 upgrade (#35377)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-18 11:16:24 +00:00
yyh
ae9c4244d6
feat(dify-ui): Meter primitive and billing adoption (#35380) 2026-04-18 07:13:54 +00:00
Stephen Zhou
3c7d6739b5
test: browser mode for dify ui (#35365) 2026-04-17 12:32:12 +00:00
Coding On Star
560195f9f4
feat(explore): implement banner impression tracking and refactor tracking logic (#35369)
Co-authored-by: CodingOnStar <hanxujiang@dify.com>
2026-04-17 12:24:34 +00:00
Asuka Minato
9ce7464c79
ci: Add conditional comment creation for diff (#35179) 2026-04-17 10:19:00 +00:00
非法操作
f980d5d3be
feat: copy nodes cross apps (#33273)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-04-17 10:02:26 +00:00
yyh
96122692cb
fix(web): keep workflow panel operator anchor mounted during menu close animation (#35363) 2026-04-17 09:10:10 +00:00
jerryzai
b9c300d570
chore(api): migrate mail task and OAuth data source to use Session(db… (#35235)
Co-authored-by: Asuka Minato <i@asukaminato.eu.org>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-17 08:52:27 +00:00
yyh
dfcc0f8863
refactor(dify-ui): finish primitive migration from web/base/ui to @langgenius/dify-ui (#35349)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-17 08:46:11 +00:00
hyl64
f56ce9d3b1
fix: guard chat file preview rendering when mime type is missing (#35355)
Co-authored-by: Stephen Zhou <hi@hyoban.cc>
2026-04-17 08:34:04 +00:00
hyl64
bd25240123
fix: raise chat settings select dropdown above dialog (#35357)
Co-authored-by: Stephen Zhou <hi@hyoban.cc>
2026-04-17 08:21:32 +00:00
YBoy
0020aa8f59
refactor(api): type pipeline template retrieval dicts with TypedDict (#34874) 2026-04-17 08:13:54 +00:00
jerryzai
e70e4fa41d
chore(api): migrate file factory builders and account commands to use Session(db.engine) (#35236)
Co-authored-by: Asuka Minato <i@asukaminato.eu.org>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-17 08:12:31 +00:00
Yunlu Wen
881a9a1a08
refactor(api): move trace providers (#35144)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-17 07:53:35 +00:00
zyssyz123
a74e12809b
fix: move remote credential validation outside DB session to prevent … (#35350)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-17 07:42:29 +00:00
Coding On Star
eaddd4a132
fix(web): stabilize workflow node panel operator dropdown trigger (#35352)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: CodingOnStar <hanxujiang@dify.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: jerryzai <jerryzh8710@protonmail.com>
Co-authored-by: NVIDIAN <speedy.hpc@hotmail.com>
Co-authored-by: ai-hpc <ai-hpc@users.noreply.github.com>
Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com>
Co-authored-by: Asuka Minato <i@asukaminato.eu.org>
Co-authored-by: Junghwan <70629228+shaun0927@users.noreply.github.com>
Co-authored-by: HeYinKazune <70251095+HeYin-OS@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-17 07:27:22 +00:00
Cocoon-Break
0c41d0bf51
fix: guard against KeyError in update_prompt_message_tool loop (#35150)
Co-authored-by: Crazywoola <100913391+crazywoola@users.noreply.github.com>
2026-04-17 07:09:40 +00:00
James
90e281c8da
test: migrate dataset service document mock tests to testcontainers (#35191)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-17 07:03:30 +00:00
sxxtony
90d638fba3
refactor: migrate DocumentSegmentSummary to TypeBase (#34862) 2026-04-17 06:58:32 +00:00
Jingyi
f5e9b02565
test: add API seeding infrastructure and app creation E2E scenarios (#35276)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 06:31:54 +00:00
Junghwan
de15e5b449
fix: scope plugin inner API end-user lookup by tenant (#35325) 2026-04-17 06:12:07 +00:00
Coding On Star
b6c7581a31
refactor(web): replace portal component with DropdownMenu in various components (#35319)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: CodingOnStar <hanxujiang@dify.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: jerryzai <jerryzh8710@protonmail.com>
Co-authored-by: NVIDIAN <speedy.hpc@hotmail.com>
Co-authored-by: ai-hpc <ai-hpc@users.noreply.github.com>
Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com>
Co-authored-by: Asuka Minato <i@asukaminato.eu.org>
Co-authored-by: Junghwan <70629228+shaun0927@users.noreply.github.com>
Co-authored-by: HeYinKazune <70251095+HeYin-OS@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-17 05:53:51 +00:00
HeYinKazune
af8ffa0654
refactor: use sessionmaker in api_tools_manage_service.py (#34892)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-17 05:07:12 +00:00
Junghwan
4d79b4a766
fix(web): stop Splash after useUserProfile errors (#35326) 2026-04-17 05:06:39 +00:00
NVIDIAN
af21dc7df8
refactor(api): migrate dataset document response schemas to BaseModel (#35298)
Co-authored-by: ai-hpc <ai-hpc@users.noreply.github.com>
Co-authored-by: Asuka Minato <i@asukaminato.eu.org>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-17 05:02:04 +00:00
yyh
dc3f992e6e
docs(web): add Storybook stories for overlay and select primitives (#35334) 2026-04-17 04:58:16 +00:00
NVIDIAN
13a9359191
refactor(api): migrate console mcp-server responses to BaseModel (#35219)
Co-authored-by: ai-hpc <ai-hpc@users.noreply.github.com>
2026-04-17 04:16:14 +00:00
jerryzai
f07f9ee7a3
chore(api): migrate event handlers to use Session(db.engine) (#35234) 2026-04-17 03:59:41 +00:00
dependabot[bot]
7396230223
chore(deps): bump pypdf from 6.10.1 to 6.10.2 in /api (#35339)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-17 03:41:02 +00:00