Skip to content

sql: add VIEWSCHEDULE and VIEWEVENTLOG system privileges#169679

Open
souravcrl wants to merge 2 commits intocockroachdb:masterfrom
souravcrl:add-viewschedule-privilege
Open

sql: add VIEWSCHEDULE and VIEWEVENTLOG system privileges#169679
souravcrl wants to merge 2 commits intocockroachdb:masterfrom
souravcrl:add-viewschedule-privilege

Conversation

@souravcrl
Copy link
Copy Markdown
Contributor

@souravcrl souravcrl commented May 4, 2026

Summary

  • Adds VIEWSCHEDULE (Kind 45) and VIEWEVENTLOG (Kind 46) system
    privileges, following the pattern of VIEWJOB, VIEWACTIVITY, etc.
  • VIEWSCHEDULE explicitly gates SHOW SCHEDULES and grants implicit
    SELECT on system.scheduled_jobs and system.jobs.
  • VIEWEVENTLOG grants read-only access to system.eventlog and the
    DB Console Events page. The gRPC Events API now accepts either
    VIEWEVENTLOG or the existing VIEWCLUSTERMETADATA.
  • Fixes the DB Console schedules API to check for SQL execution errors
    before accessing results, preventing runtime crashes on privilege errors.

Previously, SHOW SCHEDULES was implicitly gated by SELECT on
system.scheduled_jobs (admin-only), and viewing the event log required
admin or VIEWCLUSTERMETADATA — both overprivileged for users who
only need schedule or event visibility. Non-admin users can now be
granted scoped access:

GRANT SYSTEM VIEWSCHEDULE TO <user>;
GRANT SYSTEM VIEWEVENTLOG TO <user>;

Fixes: #169420
Fixes: #169421
Epic: none

Release note (sql change): Added two new system privileges:
VIEWSCHEDULE controls access to SHOW SCHEDULES, and VIEWEVENTLOG
grants read-only access to the event log. Non-admin users can be granted
scoped visibility via GRANT SYSTEM VIEWSCHEDULE TO <user> and
GRANT SYSTEM VIEWEVENTLOG TO <user> without needing broad system
table access or the admin role.

DB Console Demo

Demo

Individual Screenshots

Schedules — without VIEWSCHEDULE (error)

Schedules error

Events — without VIEWEVENTLOG (error)

Events error

Schedules — with VIEWSCHEDULE (working)

Schedules working

Events — with VIEWEVENTLOG (working)

Events working

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com

@souravcrl souravcrl requested review from a team as code owners May 4, 2026 17:29
@souravcrl souravcrl requested review from kyle-a-wong and removed request for a team May 4, 2026 17:29
@trunk-io
Copy link
Copy Markdown
Contributor

trunk-io Bot commented May 4, 2026

Merging to master in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@cockroach-teamcity
Copy link
Copy Markdown
Member

This change is Reviewable

@blathers-crl
Copy link
Copy Markdown

blathers-crl Bot commented May 4, 2026

Detected infrastructure failure (matched: self-hosted runner lost communication with the server). Automatically rerunning failed jobs. (run link)

@souravcrl souravcrl changed the title sql: add VIEWSCHEDULE system privilege for SHOW SCHEDULES sql: add VIEWSCHEDULE and VIEWEVENTLOG system privileges May 5, 2026
Comment thread pkg/sql/delegate/show_schedules.go Outdated
Comment on lines +28 to +33
if err := d.catalog.CheckPrivilege(
d.ctx, syntheticprivilege.GlobalPrivilegeObject,
d.catalog.GetCurrentUser(), privilege.VIEWSCHEDULE,
); err != nil {
return nil, err
}
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.

Bug: This upfront guard exclusively requires VIEWSCHEDULE on GlobalPrivilegeObject (a synthetic privilege object), so the VIEWSYSTEMTABLE fallback in authorization.go:264-273 — which only applies to system table descriptors — is never reached. Any non-admin user who currently accesses SHOW SCHEDULES via VIEWSYSTEMTABLE or direct SELECT grants on system.scheduled_jobs/system.jobs will get "does not have VIEWSCHEDULE system privilege" after this change, even though they have sufficient access to the underlying data.

The simplest fix is to remove this upfront guard entirely: the delegated query (SELECT ... FROM system.scheduled_jobs) will naturally hit the table-level privilege checks in authorization.go, which already correctly handle VIEWSYSTEMTABLE, VIEWSCHEDULE, and direct SELECT grants. Alternatively, expand this check to also accept VIEWSYSTEMTABLE.

Note that the analogous SHOW JOBS command has no such upfront gate, confirming this is inconsistent.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I agree with this comment. do we actually need the check here if there already is one in authorization.go?

We should be able to confirm this via a logictest.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch on the VIEWSYSTEMTABLE regression. I tested removing the upfront guard entirely and the behavior is:

  • Without the guard, the error is "user testuser does not have SELECT privilege on relation scheduled_jobs" — which doesn't tell the user what privilege they need.
  • With the guard, we get a clear "does not have VIEWSCHEDULE system privilege".

So the guard serves a UX purpose (clear error message), but as written it blocks VIEWSYSTEMTABLE users which is a regression. I've updated the guard to also check VIEWSYSTEMTABLE — if the user has neither VIEWSCHEDULE nor VIEWSYSTEMTABLE, they get the clear error. If they have VIEWSYSTEMTABLE, the guard passes and the query executes with the implicit SELECT from authorization.go.

I've also added a logictest case confirming that VIEWSYSTEMTABLE still works for SHOW SCHEDULES.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

AI Review: Potential Issue(s) Detected

An inline comment has been added to pkg/sql/delegate/show_schedules.go (lines 28-33) identifying a privilege regression.

Summary: The upfront VIEWSCHEDULE guard blocks users who previously accessed SHOW SCHEDULES via VIEWSYSTEMTABLE or direct SELECT grants on the underlying system tables. Since the check targets GlobalPrivilegeObject (a synthetic object), the VIEWSYSTEMTABLE fallback in authorization.go is never reached. This silently revokes access for non-admin users relying on existing privilege paths.

View full analysis


If helpful: add O-AI-Review-Real-Issue-Found label.
If not helpful: add O-AI-Review-Not-Helpful label.

@github-actions github-actions Bot added the o-AI-Review-Potential-Issue-Detected AI reviewer found potential issue. Never assign manually—auto-applied by GH action only. label May 5, 2026
@souravcrl
Copy link
Copy Markdown
Contributor Author

DB Console Manual Test Results

Tested the Schedules and Events pages with a non-admin user (testnopriv).

Test Flow (recorded via Playwright):

Step Page Privilege Result
1 Schedules (/#/schedules) None Error: "user testnopriv does not have VIEWSCHEDULE system privilege"
2 Events (/#/events) None Error: "user testnopriv does not have SELECT privilege on relation eventlog"
3 Schedules GRANT SYSTEM VIEWSCHEDULE Shows 2 schedules (sql-schema-telemetry, sql-stats-compaction)
4 Events GRANT SYSTEM VIEWEVENTLOG Shows event log entries
5 Schedules REVOKE SYSTEM VIEWSCHEDULE Error returns
6 Events REVOKE SYSTEM VIEWEVENTLOG Error returns

All pages display inline error alerts when privilege is missing, and render data correctly when privilege is granted.

@souravcrl souravcrl requested a review from a team May 5, 2026 07:38
Copy link
Copy Markdown
Collaborator

@rafiss rafiss left a comment

Choose a reason for hiding this comment

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

Nice work! I reviewed the privilege-related changes, and it looks good, with just a minor nit.

For changes in the frontend and RPC endpoints, please ask the o11y team.

This also seems to resolve #103341 -- i will add that issue linkage to this PR.

@rafiss made 3 comments.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on kyle-a-wong and souravcrl).


pkg/server/admin.go line 1494 at r2 (raw file):

			// Fall back to the existing VIEWCLUSTERMETADATA check.
			if err := s.privilegeChecker.RequireViewClusterMetadataPermission(ctx); err != nil {
				return nil, err

When a non-admin lacks both privileges, the user only sees "requires the VIEWCLUSTERMETADATA system privilege" — they're never told VIEWEVENTLOG would also work.

consider using errors.WithMessage so we can mention that information. another alternative would be to modify the privilegeChecker interface so both privileges can be checked with the same call.

Comment thread pkg/sql/delegate/show_schedules.go Outdated
Comment on lines +28 to +33
if err := d.catalog.CheckPrivilege(
d.ctx, syntheticprivilege.GlobalPrivilegeObject,
d.catalog.GetCurrentUser(), privilege.VIEWSCHEDULE,
); err != nil {
return nil, err
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I agree with this comment. do we actually need the check here if there already is one in authorization.go?

We should be able to confirm this via a logictest.

Previously, `SHOW SCHEDULES` was implicitly gated by `SELECT` on
`system.scheduled_jobs` and `system.jobs`, which only `admin` has by
default. This made it impossible to grant schedule visibility to
non-admin users without granting broad access to system tables.

This change introduces a new `VIEWSCHEDULE` system privilege (following
the pattern of `VIEWJOB`, `VIEWACTIVITY`, etc.) that explicitly gates
`SHOW SCHEDULES`. Admin users satisfy this check implicitly through
`ALL` privileges. The privilege also grants implicit `SELECT` on
`system.scheduled_jobs` and `system.jobs` so the delegated query
executes successfully.

The delegator check is kept (rather than relying solely on the
authorization.go fallback) because without it the user would see a
confusing "does not have SELECT privilege on relation scheduled_jobs"
error instead of a clear message about the VIEWSCHEDULE privilege.

On the DB Console side, the schedules API now checks for SQL execution
errors before accessing results, preventing runtime crashes when the
user lacks the required privilege.

Fixes: cockroachdb#169420
Epic: none
Release note (sql change): Added a new `VIEWSCHEDULE` system privilege
that controls access to `SHOW SCHEDULES`. Non-admin users can be granted
schedule visibility via `GRANT SYSTEM VIEWSCHEDULE TO <user>` without
needing direct `SELECT` on system tables.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@souravcrl souravcrl force-pushed the add-viewschedule-privilege branch from ca60e3f to 8b57f1a Compare May 6, 2026 09:34
Previously, viewing the event log required `admin` or
`VIEWCLUSTERMETADATA`, both of which are overprivileged for users who
only need to read cluster events (e.g. SREs and auditors correlating
events during incidents).

This change introduces a new `VIEWEVENTLOG` system privilege that
grants read-only access to `system.eventlog`. The gRPC Events API now
accepts either `VIEWEVENTLOG` or the existing `VIEWCLUSTERMETADATA`
privilege, and the error message mentions both options. The privilege
also grants implicit `SELECT` on `system.eventlog` so the DB Console
SQL-based events page works correctly.

Non-admin users can now be granted event log visibility via:
```sql
GRANT SYSTEM VIEWEVENTLOG TO <user>;
```

Fixes: cockroachdb#169421
Epic: none
Release note (sql change): Added a new `VIEWEVENTLOG` system privilege
that grants read-only access to the event log. Non-admin users can be
granted event log visibility via `GRANT SYSTEM VIEWEVENTLOG TO <user>`
without needing `VIEWCLUSTERMETADATA` or the `admin` role.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@souravcrl souravcrl force-pushed the add-viewschedule-privilege branch from 8b57f1a to 7057256 Compare May 6, 2026 09:42
@souravcrl souravcrl requested a review from rafiss May 6, 2026 10:12
Copy link
Copy Markdown
Contributor Author

@souravcrl souravcrl left a comment

Choose a reason for hiding this comment

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

@souravcrl made 1 comment.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on kyle-a-wong and rafiss).


pkg/server/admin.go line 1494 at r2 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

When a non-admin lacks both privileges, the user only sees "requires the VIEWCLUSTERMETADATA system privilege" — they're never told VIEWEVENTLOG would also work.

consider using errors.WithMessage so we can mention that information. another alternative would be to modify the privilegeChecker interface so both privileges can be checked with the same call.

done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

o-AI-Review-Potential-Issue-Detected AI reviewer found potential issue. Never assign manually—auto-applied by GH action only.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sql: add VIEWEVENTLOG system privilege for scoped event log visibility sql: add VIEWSCHEDULE system privilege for scoped schedule visibility

3 participants