Skip to content

[codex] Allow project admin to manage extensions#4

Merged
Fermionic-Lyu merged 3 commits into
mainfrom
codex/project-admin-extension-hook
May 28, 2026
Merged

[codex] Allow project admin to manage extensions#4
Fermionic-Lyu merged 3 commits into
mainfrom
codex/project-admin-extension-hook

Conversation

@Fermionic-Lyu

@Fermionic-Lyu Fermionic-Lyu commented May 28, 2026

Copy link
Copy Markdown
Member

Summary

  • Add an insforge.extension_grant_role GUC, defaulting to project_admin.
  • Route CREATE/ALTER/DROP EXTENSION utility statements from that role through the existing insforge_pg_utils preload hook as the bootstrap superuser.
  • Refactor the utility hook into statement-class handlers with shared ProcessUtility call context and shared user-context switching.
  • Document the broader utility permission hook behavior.

Why

Raw SQL now runs as project_admin, which cannot install extensions that require superuser privileges. This keeps database-level CREATE ungranted, avoids changing extension control files, and scopes the bypass to extension utility statements.

The hook now has more than one responsibility, so the dispatcher shape keeps policy and extension handling separate while reusing the low-level execution plumbing.

Validation

  • git diff --check
  • docker build -t insforge-postgres-hook-test ./postgres
  • Smoke-tested a temporary container with the InsForge postgresql.conf: project_admin can CREATE EXTENSION vector and DROP EXTENSION vector; project_admin still cannot CREATE SCHEMA or CREATE PUBLICATION; a regular app_user still cannot CREATE EXTENSION vector.

@Fermionic-Lyu Fermionic-Lyu marked this pull request as ready for review May 28, 2026 19:12

@tonychang04 tonychang04 left a comment

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.

Review — [codex] Allow project admin to manage extensions

Code quality: 👍 The refactor into the InsforgeUtilityCall struct + handle_policy_utility / handle_extension_utility dispatchers is clean and removes the long parameter lists. The privileged user-context switch in run_as_user is the correct Postgres idiomGetUserIdAndSecContextSetUserIdAndSecContext(target, ... | SECURITY_LOCAL_USERID_CHANGE)PG_TRY, with the role restored on both the PG_CATCH (re-throw) and success (after PG_END_TRY) paths. No leak of superuser context, and no recursion risk (re-entry runs as BOOTSTRAP_SUPERUSERID so !superuser() short-circuits the hook). The statement gate (is_extension_utility_statement) is correctly scoped to CREATE/ALTER/AlterContents/DROP-EXTENSION node tags.

⚠️ One security consideration to confirm before merge: no extension allowlist

handle_extension_utility elevates any CREATE EXTENSION <x> from project_admin to run as BOOTSTRAP_SUPERUSERID, with no restriction on which extension. The Postgres image (postgres/Dockerfile) installs postgresql-contrib-15, which ships several extensions whose install scripts/functions are sensitive when created by superuser:

  • file_fdw (read server files), adminpack (pg_file_write/pg_file_unlink), dblink / postgres_fdw (outbound connections → SSRF to internal services), plus pg_net (HTTP).

Good news: the image does not ship untrusted PLs (plpython3u / plperlu), so there's no direct code-exec via untrusted language. And many of those contrib functions stay superuser-gated at EXECUTE time independent of who owns them — so this isn't necessarily a clean RCE. But it does meaningfully widen the attack surface for a non-superuser role.

Recommendation: add an allowlist of permitted extension names (e.g. a insforge.extension_allow_list GUC checked against stmt->extname in handle_extension_utility), defaulting to the intended set (vector, pg_graphql, pg_net, postgis, pg_trgm, uuid-ossp, ...). That keeps the feature's value while preventing project_admin from installing file_fdw/dblink/adminpack/postgres_fdw. At minimum, please confirm those contrib extensions' privileged functions remain superuser-gated post-install so installation alone isn't exploitable.

(Also nice-to-have: audit-log each elevated extension statement — who ran what — for traceability.)

Not blocking on the refactor itself, which is solid; flagging the allowlist as the one thing worth deciding explicitly before this ships.

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 3 files

Re-trigger cubic

@tonychang04 tonychang04 left a comment

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.

Approved per fermioniclyu — proceeding without the extension allowlist for now (security note left in prior review comment for the record: no untrusted PLs shipped, and contrib functions stay superuser-gated at EXECUTE).

@Fermionic-Lyu Fermionic-Lyu merged commit 86f0653 into main May 28, 2026
2 checks passed
@Fermionic-Lyu Fermionic-Lyu deleted the codex/project-admin-extension-hook branch May 28, 2026 19:20
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