Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The status query has unresolved authorization behavior and requires additional integration coverage.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds secure, auditable personal Postgres access management through GraphQL, authorization, RBAC, persistence, and integration tests.
Changes:
- Adds access creation, status, and credential retrieval.
- Adds authorization, auditing, migration, and Kubernetes RBAC support.
- Adds models, resolvers, generated schema code, tests, and fixtures.
File summaries
| File | Summary |
|---|---|
internal/persistence/postgres/queries.go |
Access creation and retrieval logic |
internal/persistence/postgres/queries_test.go |
Unit tests for access handling |
internal/persistence/postgres/node.go |
Node identification support |
internal/persistence/postgres/models.go |
Access models and validation |
internal/persistence/postgres/activitylog.go |
Access audit transformations |
internal/graph/schema/postgres.graphqls |
GraphQL schema additions |
internal/graph/postgres.resolvers.go |
GraphQL resolvers |
internal/graph/gengql/schema.generated.go |
Generated schema execution code |
internal/graph/gengql/root_.generated.go |
Generated resolver metadata |
internal/graph/gengql/activitylog.generated.go |
Generated activity-log support |
internal/database/migrations/0075_add_postgres_access_read_authorization.sql |
Read authorization migration |
internal/auth/authz/queries.go |
Postgres access authorization checks |
integration_tests/k8s_resources/create_postgres_access/dev/someteamname/secret_ready_access_credentials.yaml |
Ready credential fixture |
integration_tests/k8s_resources/create_postgres_access/dev/someteamname/postgres_progressing.yaml |
Progressing instance fixture |
integration_tests/k8s_resources/create_postgres_access/dev/someteamname/postgres_foobar.yaml |
Available instance fixture |
integration_tests/k8s_resources/create_postgres_access/dev/someteamname/postgres_access_ready.yaml |
Ready access fixture |
integration_tests/k8s_resources/create_postgres_access/dev/someteamname/postgres_access_pending-access.yaml |
Pending access fixture |
integration_tests/k8s_resources/create_postgres_access/dev/someteamname/postgres_access_missing-secret-access.yaml |
Missing-secret fixture |
integration_tests/k8s_resources/create_postgres_access/dev/someteamname/postgres_access_expired-access.yaml |
Expired access fixture |
integration_tests/create_postgres_access.lua |
Integration coverage for access flows |
charts/console-backend-rbac/templates/rbac.yaml |
Kubernetes RBAC permissions |
Review details
Files not reviewed (2)
- internal/graph/gengql/activitylog.generated.go: Generated file
- internal/graph/gengql/schema.generated.go: Generated file
Suppressed comments (15)
internal/graph/schema/postgres.graphqls:266
- The newly added activity-log schema types/data type are missing the required public descriptions (and the data fields are undocumented). Add descriptions for the type and each field before exposing this schema.
type PostgresPersonalAccessCreatedActivityLogEntryData {
username: String!
expiresAt: Time!
reason: String!
internal/graph/schema/postgres.graphqls:338
- The new
CreatePostgresAccessPayloadtype and its fields are missing the required public descriptions. Add developer-facing descriptions before exposing this payload in the schema.
type CreatePostgresAccessPayload {
"Name of the newly created PostgresAccess resource."
name: String!
"Server-controlled expiry for this personal access."
expiresAt: Time!
internal/graph/schema/postgres.graphqls:345
- The new input type and its fields are largely undocumented; only
reasonhas a description. Add descriptions for the input and every field, including the access-level and client-key semantics.
input CreatePostgresAccessInput {
postgresInstance: String!
teamSlug: Slug!
environmentName: String!
accessLevel: PostgresAccessLevel!
internal/graph/schema/postgres.graphqls:354
- The new
PostgresAccessLevelenum and all of its values lack descriptions. Add developer-facing descriptions for the enum and each value.
enum PostgresAccessLevel {
READ
READWRITE
READWRITECREATE
internal/graph/schema/postgres.graphqls:412
- The new
PostgresAccesstype and itsid/namefields omit the required descriptions. Add a type description and explain these fields in the public schema.
type PostgresAccess implements Node {
id: ID!
name: String!
internal/graph/schema/postgres.graphqls:435
- The new
PostgresAccessStateenum and all values lack descriptions. Add developer-facing descriptions for the enum and each state.
enum PostgresAccessState {
PENDING
READY
FAILED
EXPIRED
internal/graph/schema/postgres.graphqls:450
- The new connection input type and its fields are missing public descriptions. Add descriptions for the type and each input field.
input PostgresAccessConnectionInput {
name: String!
teamSlug: Slug!
environmentName: String!
internal/graph/schema/postgres.graphqls:457
- The new connection payload type and its fields are missing public descriptions. Add descriptions for the type and each returned field, especially the sensitive credential fields.
type PostgresAccessConnectionPayload {
password: String!
caCertificate: String!
serverName: String!
tunnel: PostgresAccessConnectionTunnel!
internal/graph/schema/postgres.graphqls:463
- The new connection tunnel type and both fields are missing public descriptions. Add descriptions explaining the endpoint and gateway key.
type PostgresAccessConnectionTunnel {
endpoint: String!
gatewayPublicKey: String!
}
internal/graph/schema/postgres.graphqls:438
- The new
PostgresAccessTunneltype itself lacks a description even though its fields are documented. Add a developer-facing type description.
type PostgresAccessTunnel {
internal/graph/schema/postgres.graphqls:273
- The new personal-access-connection activity-log type and its fields are all missing public descriptions. Add descriptions for the type and every field.
type PostgresPersonalAccessConnectionActivityLogEntry implements ActivityLogEntry & Node {
id: ID!
actor: String!
createdAt: Time!
message: String!
internal/graph/schema/postgres.graphqls:451
- The connection input and the response types below are public schema additions but have no descriptions on their types or fields. Add developer-facing descriptions for the input, payload, tunnel, and every field before publishing them.
input PostgresAccessConnectionInput {
name: String!
teamSlug: Slug!
environmentName: String!
}
internal/graph/schema/postgres.graphqls:457
- The connection payload and tunnel types expose credentials and connection metadata without GraphQL descriptions. Document the types and each field, particularly password and caCertificate, so consumers understand the sensitivity and purpose of these values.
type PostgresAccessConnectionPayload {
password: String!
caCertificate: String!
serverName: String!
tunnel: PostgresAccessConnectionTunnel!
internal/persistence/postgres/queries.go:156
CanReadPostgresAccessgrants this operation to team members, but this additional owner check rejects every non-owner withPostgresAccess not found. That makes the new read authorization ineffective for the status query and conflicts with the migration's Team member role; keep the owner-only check for credentials if intended, but allow authorized team members to read status.
actor := authz.ActorFromContext(ctx)
if actor == nil || access.Username != actor.User.Identity() {
return nil, apierror.Errorf("PostgresAccess %q not found", name)
}
internal/persistence/postgres/queries.go:128
- The new public status query/Node lookup is not exercised by the added integration tests; they cover only connection retrieval and helper functions. Add an integration test for
postgresAccess(including pending/expired state mapping and a different-owner request) because this path contains the ownership and status exposure checks.
func GetPostgresAccessByIdent(ctx context.Context, id ident.Ident) (*PostgresAccess, error) {
teamSlug, environmentName, name, err := parseAccessIdent(id)
if err != nil {
return nil, err
}
return GetPostgresAccess(ctx, name, teamSlug, environmentName)
- Files reviewed: 25/28 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This pull request introduces support for personal Postgres access management via the API, including new authorizations, RBAC rules, GraphQL mutations and queries, and comprehensive integration tests. The changes ensure that users can request, retrieve, and audit personal Postgres access securely, with fine-grained authorization checks and proper activity logging.
API and Authorization Enhancements:
postgres:access:readauthorization, granting team members and owners permission to read personal Postgres access status and credentials. This is enforced via a newCanReadPostgresAccessfunction and corresponding database migration. [1] [2]getandcreateverbs for thepostgresaccessesresource in thenais.ioAPI group, enabling the necessary Kubernetes permissions for managing Postgres access. [1] [2]GraphQL API Additions:
createPostgresAccessmutation andpostgresAccessConnectionandpostgresAccessqueries, along with their input types and resolvers, to support creation and retrieval of personal Postgres access and connection credentials. [1] [2] [3] [4] [5]Integration Tests and Fixtures:
create_postgres_access.luato cover authorization, error cases (such as unknown/unavailable instances), successful access creation, credential retrieval, and auditing.These changes collectively enable secure and auditable management of personal Postgres access for team members via the API.
References:
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18]