Skip to content

feat: add authz policy types to _meta GraphQL API#852

Open
pyramation wants to merge 2 commits intomainfrom
devin/1773915352-smart-tags-authz
Open

feat: add authz policy types to _meta GraphQL API#852
pyramation wants to merge 2 commits intomainfrom
devin/1773915352-smart-tags-authz

Conversation

@pyramation
Copy link
Contributor

@pyramation pyramation commented Mar 19, 2026

Summary

Adds authorization policy metadata to the _meta GraphQL introspection API, allowing clients to query @authz policy information on tables. This is the constructive side of a cross-repo feature — the companion PR in constructive-db implements the SQL infrastructure (policy ↔ smart tag sync, validation, permission simulation).

Changes:

  • New TypeScript interfaces: AuthzGrantMeta, AuthzPolicyMeta in types.ts
  • New GraphQL types: MetaAuthzGrant, MetaAuthzPolicy in graphql-meta-field.ts
  • New optional authz field on MetaTable (nullable list of MetaAuthzPolicy)
  • New authz-meta-builder.ts — reads @authz smart tags from PostGraphile codec extensions (codec.extensions.tags.authz) and transforms them into AuthzPolicyMeta[] with human-readable descriptions
  • Wired into table-meta-builder.ts so collectTablesMeta() populates authz on each TableMeta

How population works:
buildAuthzMeta(codec) reads codec.extensions.tags.authz (where PostGraphile v5 stores smart tags from COMMENT ON), parses the @authz JSON array, and maps each entry to an AuthzPolicyMeta with a generated description string. A hardcoded POLICY_DESCRIPTIONS map covers all known Authz node types (AuthzDirectOwner, AuthzEntityMembership, AuthzAllowAll, etc.) with context-aware messages like "Requires membership on entity referenced by owner_id with admin_group permission". Unknown policy types fall back to the type name itself.

What this does NOT include yet:

  • Role-based scoping (admin sees full config, user sees type+description, anon sees nothing) — authz is exposed unconditionally on MetaTable

Review & Testing Checklist for Human

  • Verify codec.extensions.tags.authz is actually populated: The builder reads smart tags from PostGraphile's codec extensions. Confirm that @authz tags written to COMMENT ON TABLE by the constructive-db write-back trigger flow through PostGraphile introspection into codec.extensions.tags.authz. If PostGraphile stores the tag differently (e.g., as a flat string vs. parsed JSON), the parsing logic in buildAuthzMeta may need adjustment.
  • PgCodecWithTags type cast: buildAuthzMeta casts PgCodec to PgCodecWithTags to access extensions.tags. The existing PgCodec type in types.ts only declares extensions.pg — verify this cast is safe and doesn't mask type errors elsewhere.
  • POLICY_DESCRIPTIONS coverage: The description map is hardcoded against known node_type_registry entries. If new Authz node types are added in the DB, they'll get the type name as their description (fallback). Confirm this fallback is acceptable.
  • No role-based scoping: authz is exposed to all users unconditionally. Before production use, this needs scoping so anonymous/unauthenticated users don't see policy metadata.
  • No tests: Neither the description generation, tag parsing, nor GraphQL schema shape have test coverage. Consider adding at least a unit test for buildAuthzMeta with sample tag data.

Recommended test plan:

  1. Apply an @authz smart tag to a table via COMMENT ON TABLE ... '@authz [{"policy_type":"AuthzAllowAll","grants":[["select","authenticated"]]}]'
  2. Start the GraphQL server and query { _meta { tables { name authz { policyType description grants { privilege role } permissive } } } }
  3. Verify the table with the tag returns populated authz array; tables without tags return null

Notes

  • This PR is part of a multi-repo effort. The constructive-db companion PR adds: validate_authz_tag(), rebuild_table_authz_tags(), policy write-back trigger, compile_authz_tags() bridge, check_table_permission() simulation, and parse_comment_to_smart_tags().
  • The authz field is nullable (not nn()), so existing queries won't break — tables without @authz tags return null.
  • description is NonNull on MetaAuthzPolicyType but describePolicy() always returns a string (falling back to the policy type name), so this is safe as long as population only goes through buildAuthzMeta.

Link to Devin session: https://app.devin.ai/sessions/8a124626a9f04ee9ac2f608b77d2921b
Requested by: @pyramation

- Add AuthzGrantMeta and AuthzPolicyMeta TypeScript interfaces
- Add MetaAuthzGrant and MetaAuthzPolicy GraphQL types
- Add authz field to MetaTable for policy introspection via _meta query
- Supports role-based scoping (full config for admins, type+description for users)
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

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.

1 participant