Skip to content

feat(postgres): add create/update mutations and reuse live personal access - #535

Merged
jhrv merged 5 commits into
mainfrom
create-postgres
Oct 2, 2026
Merged

jhrv merged 5 commits into
mainfrom
create-postgres

Conversation

@jhrv

@jhrv jhrv commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Adds API-backed create/update for Postgres, following the Valkey pattern, and makes personal access idempotent.

Postgres create/update

  • createPostgres / updatePostgres mutations, authorized by new postgres:create and postgres:update permissions (members and owners). Developers get no direct write access to the CRDs.
  • Only major version 18 is accepted. Omitted cpu/memory/diskSize are left out so CRD defaults apply. Names must be DNS-1123 subdomains; quantities must be > 0.
  • POSTGRES_CREATED / POSTGRES_UPDATED activity log entries; updates log updatedFields (field, old and new value).

Personal access (PostgresAccess)

  • Deterministic name per (user, branch), so concurrent requests are serialized by the API server. A live access with the same level is reused, a different level is rejected, and an expired one is deleted and the caller asked to retry. This needs delete on postgresaccesses in RBAC.
  • PostgresAccess.connection returns null (no error) until the access is READY.

Tests

New postgres_crud suite; create_postgres_access covers reuse, conflicts and expired cleanup.

@jhrv
jhrv requested a review from a team as a code owner October 1, 2026 12:45
@jhrv
jhrv requested a balanced review from Copilot October 1, 2026 12:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Concurrent access creation can violate uniqueness, and input validation and schema documentation remain incomplete.

Review effort: Balanced
Findings: 1 High severity · 3 Medium severity · 1 Low severity

Open (5)
What changed in this PR

Adds Postgres create/update API support, authorization, audit logging, RBAC, and personal-access reuse.

Changes:

  • Adds authorized GraphQL mutations for creating and updating Postgres instances.
  • Adds audit events, permissions, RBAC, and generated GraphQL support.
  • Expands integration coverage and reuses active personal access.
File Description
internal/​persistence/​postgres/​write.go Implements create/update operations and validation.
internal/​persistence/​postgres/​queries.go Reuses active access and adjusts connection readiness.
internal/​persistence/​postgres/​activitylog.go Registers create/update audit events.
internal/​kubernetes/​fake/​fake.go Adds fake-client list support.
internal/​graph/​schema/​postgres.graphqls Defines mutations, inputs, payloads, and audit types.
internal/​graph/​postgres.resolvers.go Connects mutations to authorization and persistence.
internal/​graph/​gengql/​schema.generated.go Updates generated resolver wiring.
internal/​graph/​gengql/​root_.generated.go Updates generated schema and complexity metadata.
internal/​graph/​gengql/​postgres.generated.go Adds generated Postgres GraphQL handling.
internal/​graph/​gengql/​activitylog.generated.go Adds generated audit-entry dispatch.
internal/​database/​migrations/​0077_add_postgres_create_update_authorizations.sql Adds create/update permissions.
internal/​auth/​authz/​queries.go Adds authorization checks.
integration_tests/​postgres_crud.lua Tests create/update behavior and authorization.
integration_tests/​k8s_resources/​postgres_crud/​dev/​pg-crud-team/​postgres.yaml Provides CRUD test fixture.
integration_tests/​create_postgres_access.lua Tests access reuse and readiness behavior.
charts/​console-backend-rbac/​templates/​rbac.yaml Grants required Kubernetes operations.
Files not reviewed (3)
  • internal/graph/gengql/activitylog.generated.go: Generated file
  • internal/graph/gengql/postgres.generated.go: Generated file
  • internal/graph/gengql/schema.generated.go: Generated file

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/persistence/postgres/queries.go Outdated
Comment thread internal/persistence/postgres/activitylog.go
Comment thread internal/persistence/postgres/write.go Outdated
Comment thread internal/persistence/postgres/write.go Outdated
Comment thread internal/graph/schema/postgres.graphqls
@jhrv
jhrv requested a balanced review from Copilot October 1, 2026 16:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Omitted resources become zero-valued and on-prem deployments lack the new write permissions.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
Resolved since last review (4)
Files not reviewed (3)
  • internal/graph/gengql/activitylog.generated.go: Generated file
  • internal/graph/gengql/postgres.generated.go: Generated file
  • internal/graph/gengql/schema.generated.go: Generated file
Previously missed (2)

In code that hasn't changed since last review

Medium severity On-prem ClusterRole lacks create and update permissions

charts/​console-backend-rbac/​templates/​rbac.yaml:131

The write verbs are added only to the tenant ClusterRole. The on-prem ClusterRole still grants postgres only get, list, and watch (lines 302–308), while these mutations use the system-authenticated client with no environment-kind guard. Consequently, create/update requests against an on-prem environment will pass API authorization but fail with Kubernetes Forbidden; mirror create and update in the on-prem rule.

Medium severity Omitted resource fields serialize as zero values instead of CRD defaults

internal/​persistence/​postgres/​write.go:175

Omitting resource fields does not leave them to the CRD defaults. PostgresResources and its resource.Quantity fields are value structs, and DefaultUnstructuredConverter does not treat structs as empty for omitempty, so this emits cpu, memory, and diskSize as "0". The CRD therefore cannot apply its 100m/512Mi/10Gi defaults; toPostgres masks these zero values as null, so the integration assertion does not catch the malformed resource. Remove keys for omitted inputs before calling Create.

Comment thread charts/console-backend-rbac/templates/rbac.yaml
Comment thread internal/graph/schema/postgres.graphqls Outdated
Comment thread internal/graph/schema/postgres.graphqls Outdated
Comment thread internal/persistence/postgres/write.go Outdated
Comment thread internal/persistence/postgres/write.go Outdated
Comment thread internal/persistence/postgres/write.go Outdated
Comment thread internal/persistence/postgres/write.go Outdated
Comment thread internal/persistence/postgres/write.go Outdated
@jhrv
jhrv requested a balanced review from Copilot October 1, 2026 20:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Onprem write permissions and compatibility with existing personal accesses still need correction.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)
Files not reviewed (3)
  • internal/graph/gengql/activitylog.generated.go: Generated file
  • internal/graph/gengql/postgres.generated.go: Generated file
  • internal/graph/gengql/schema.generated.go: Generated file
Previously missed (1)

In code that hasn't changed since last review

Medium severity Reuse live legacy accesses before creating deterministic resources

internal/​persistence/​postgres/​queries.go:504

Before this change, personal accesses used random postgres-access-<8 hex> names. A still-live access with that name will not conflict with the new deterministic name, so a repeat request after rollout creates another access for the same user and branch. Under the single-role constraint described above, the second access cannot become ready. Before creating the deterministic resource, look up accesses by spec.username and spec.postgresBranch; reuse a live match with the same access level and reject a different level. Return the existing object's name and expiry, and grant list on postgresaccesses in both RBAC branches. Cover a live legacy-named access in an integration test.

Comment thread charts/console-backend-rbac/templates/rbac.yaml
@jhrv

jhrv commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

Re. Copilot's "Reuse live legacy accesses before creating deterministic resources": not planned. The personal access flow is unreleased, so the only random-named postgres-access-<8hex> objects are test objects from relay testing in nav-dev. Their TTL is at most 1 hour, so they have already expired. Looking them up would need list on postgresaccesses in both RBAC roles plus a separate reuse path, for something that goes away on its own.

@jhrv
jhrv merged commit fedecf4 into main Oct 2, 2026
14 checks passed
@jhrv
jhrv deleted the create-postgres branch October 2, 2026 07:31
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.

3 participants