Skip to content

feat(files): per-volume in-app policy enforcement#197

Open
atilafassina wants to merge 14 commits intomainfrom
files/service-principal-policies
Open

feat(files): per-volume in-app policy enforcement#197
atilafassina wants to merge 14 commits intomainfrom
files/service-principal-policies

Conversation

@atilafassina
Copy link
Copy Markdown
Contributor

@atilafassina atilafassina commented Mar 18, 2026

Summary

  • Per-volume policy system: FilePolicy — a function (action, resource, user) → boolean — gates every file operation before the Databricks API call. Ships with built-in helpers (policy.publicRead(), policy.allowAll(), policy.denyAll()) and combinators (all, any, not) for composition.
  • Service-principal execution model: HTTP routes now always execute as the service principal. The policy layer becomes the app-level gate — user identity is extracted from x-forwarded-user and passed to the policy function.
  • Safe defaults: Volumes without an explicit policy default to publicRead() (read-only). A startup warning encourages setting an explicit policy.

Motivation

Previously the files plugin relied entirely on OBO token forwarding and Unity Catalog grants. This meant:

  1. No app-level way to restrict per-user operations (e.g. allow reads but deny uploads).
  2. The SP's credentials were always used on HTTP routes regardless of UC grants.

Policies close this gap with a composable, per-volume authorization layer evaluated before any API call.

Key changes

Area Details
policy.ts (new) FileAction, FileResource, FilePolicyUser types · PolicyDeniedError · policy namespace with publicRead(), allowAll(), denyAll(), all(), any(), not()
plugin.ts Policy enforcement wired into every route handler and programmatic API · Removed isInUserContext/OBO gating · Added _enforcePolicy(), _checkPolicy(), _extractUser() · _executeOrThrow() for proper 4xx propagation
types.ts policy?: FilePolicy on VolumeConfig · Updated JSDoc to reflect SP-first execution model
index.ts Re-exports policy from top-level barrel
dev-playground Updated to use policy.allowAll() on the default volume
docs Full plugin docs (files.md) with permission model, built-in policies, combinators, custom policies · Generated API reference for policy namespace

Test coverage

  • Policy combinators (policy.test.ts): all helpers, async policies, PolicyDeniedError, edge cases
  • Plugin enforcement (plugin.test.ts): route-level 401/403 responses, SDK API with user/SP identity, upload size in resource, cache invalidation under SP model
  • Integration tests updated for the policy-first model

Test plan

  • Unit tests for policy combinators and helpers
  • Unit tests for plugin policy enforcement across all route handlers
  • Existing plugin tests updated for new execution model
  • Linting and type checks pass
  • Manual verification against a Databricks workspace via pnpm dev

This pull request was AI-assisted by Isaac.

@atilafassina atilafassina self-assigned this Mar 26, 2026
@atilafassina atilafassina marked this pull request as ready for review March 26, 2026 13:56
Copy link
Copy Markdown
Member

@pkosiec pkosiec left a comment

Choose a reason for hiding this comment

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

Great work! Overall LGTM, pls see my small comments on the proposal and here - they might affect some methods naming etc.

Disclaimer: unfortunately I wasn't able to test it, I'll run it next week 👍 Unless you could record a short, raw demo video showcasing how the policies work ?

Also, I think it would be worth if we had approval for at least the RFC from Fabian / Mario who were much more involved in the files discussions. Thanks!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not sure if we shouldn't update the AppKit template to utilize the policies for the sample path?

And the same with an agent skill for files? Agent might be confused without additional guidance - we need to verify that.

Copilot AI review requested due to automatic review settings April 2, 2026 15:18
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds an in-app, per-volume authorization layer to the Files plugin via composable FilePolicy functions, and updates the plugin so HTTP routes execute using the service principal while enforcing access decisions through policies (user identity taken from x-forwarded-user).

Changes:

  • Introduces FilePolicy types/helpers (policy.* combinators, PolicyDeniedError, READ/WRITE action sets) and wires policy checks into HTTP handlers and the programmatic Volume API.
  • Switches route execution to service-principal-first and enforces user identity presence (401) + policy decisions (403) before upstream Databricks calls.
  • Updates tests and documentation to reflect the new policy model and default publicRead() behavior.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
packages/appkit/src/plugins/files/policy.ts Adds policy types, helpers, combinators, and PolicyDeniedError.
packages/appkit/src/plugins/files/plugin.ts Enforces policies on routes and SDK API; defaults volumes to publicRead(); removes user-context gating.
packages/appkit/src/plugins/files/types.ts Adds policy?: FilePolicy to VolumeConfig and updates public API docs.
packages/appkit/src/plugins/files/index.ts Re-exports policy symbols from the files plugin barrel.
packages/appkit/src/index.ts Exposes policy at top-level @databricks/appkit.
packages/appkit/src/context/* Removes isInUserContext and introduces getCurrentUserId usage for caching/identity.
packages/appkit/src/plugins/files/tests/policy.test.ts Unit tests for policy helpers/combinators.
packages/appkit/src/plugins/files/tests/plugin.test.ts Adds policy enforcement tests and updates behavior expectations (SP execution).
packages/appkit/src/plugins/files/tests/plugin.integration.test.ts Updates integration tests for SP execution + default publicRead() denying writes.
apps/dev-playground/server/index.ts Configures dev-playground volume with policy.allowAll().
docs/docs/plugins/files.md Documents the new policy model and enforcement semantics.
docs/docs/api/appkit/Variable.policy.md Adds API reference page for policy.
docs/docs/api/appkit/index.md Adds policy to API index.
docs/docs/api/appkit/typedoc-sidebar.ts Adds policy to Typedoc sidebar.
docs/static/appkit-ui/styles.gen.css Updates selection styling using color-mix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


#### Enforcement

- **HTTP routes**: Policy checked before every operation. Denied → `403` JSON response with `"Action denied by volume policy"`.
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

The documented 403 error message for HTTP routes ("Action denied by volume policy") doesn’t match the actual PolicyDeniedError message returned by the plugin (Policy denied "{action}" on volume "{volumeKey}"). Update this text so users can rely on the documented response body.

Suggested change
- **HTTP routes**: Policy checked before every operation. Denied → `403` JSON response with `"Action denied by volume policy"`.
- **HTTP routes**: Policy checked before every operation. Denied → `403` JSON response with `Policy denied "{action}" on volume "{volumeKey}"`.

Copilot uses AI. Check for mistakes.
@databricks databricks deleted a comment from Copilot AI Apr 2, 2026
@databricks databricks deleted a comment from Copilot AI Apr 2, 2026
@databricks databricks deleted a comment from Copilot AI Apr 2, 2026
@databricks databricks deleted a comment from Copilot AI Apr 2, 2026
@databricks databricks deleted a comment from Copilot AI Apr 2, 2026
@databricks databricks deleted a comment from Copilot AI Apr 2, 2026
@databricks databricks deleted a comment from Copilot AI Apr 2, 2026
@databricks databricks deleted a comment from Copilot AI Apr 2, 2026
@databricks databricks deleted a comment from Copilot AI Apr 2, 2026
@databricks databricks deleted a comment from Copilot AI Apr 2, 2026
@atilafassina atilafassina changed the title feat(files): In-App Policy support feat(files): per-volume in-app policy enforcement Apr 2, 2026
@atilafassina atilafassina force-pushed the files/service-principal-policies branch from e43da85 to edabf4b Compare April 2, 2026 19:27
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.

4 participants