Enforce fine-grained CloudEvent grants#6
Draft
elffjs wants to merge 1 commit into
Draft
Conversation
Restore telemetry-api's narrow `cloud_events` JWT grant support, which
fetch-api never had and which the merged service inherited as coarse-only.
The CloudEvent queries (cloudEvents, latestCloudEvent,
availableCloudEventTypes) now authorize a request via either of two
independent paths, OR'd together:
1. Full access via the permissions enum (GetRawData, or the
GetLocationHistory + GetNonLocationHistory combo).
2. A scoped cloud_events grant, evaluated independently of the enum,
authorizing specific event types / sources / ids.
Enforcement is up-front and fail-closed (ported from telemetry-api's
validCloudEventRequest): a request is allowed only if its filter falls
entirely within a single grant, with unset filter dimensions defaulting
to the "*" wildcard. We validate rather than post-filter results, so a
request that cannot be fully served is rejected instead of partially
serviced. Subject-DID scoping still applies in both paths.
The single chokepoint (requireSubjectOptsByDID) covers all three
resolvers and the MCP surface. The internal gRPC FetchService remains an
unauthenticated, trusted surface by design and is out of scope.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
dqis a fusion of telemetry-api and fetch-api. telemetry-api could honor a narrowcloud_eventsJWT grant — authorizing specific event types, from specific sources, optionally pinned to specific IDs, rather than coarse "read all cloud events." fetch-api never had this, and the merged service inherited fetch-api's coarse-only check. Thecloud_eventsgrant already arrived in context but was never consulted.This restores the capability. It's security-sensitive — the default is fail-closed.
Approach
Two independent authorization paths for the CloudEvent queries (
cloudEvents,latestCloudEvent,availableCloudEventTypes), OR'd together — a request is allowed if either applies:permissions—GetRawData, or theGetLocationHistory+GetNonLocationHistorycombo. Reads all of the subject's events (unchanged behavior).cloud_eventsgrant — evaluated independently of the permissions enum; the grant is self-authorizing.Enforcement is up-front and fail-closed (
cloudEventRequestAllowed/grantCovers, ported from telemetry-api'svalidCloudEventRequest): a request is authorized only if its filter falls entirely within a single grant. Unset filter dimensions default to the*wildcard, so a narrow grant requires the caller to scope their query to match it. We validate rather than post-filter results — a request that can't be fully served is rejected, not partially serviced. Subject-DID scoping still applies in both paths.AdvancedSearchOptionsAND's its top-level fields and only OR's within a single field, so the OR-of-ANDs grant model can't be losslessly pushed into one query — validating the request (gate, don't rewrite) is the clean fit.Scope
requireSubjectOptsByDIDcovers all three resolvers and the MCP surface (same resolvers via@mcpTool). No resolver changes needed.DQClaim→tokenclaims.Token.CloudEvents.Out of scope
FetchServiceremains an unauthenticated, network-isolated, trusted surface by design — grants are not enforced there.tagsare not checked (notagsfield onCloudEventFilter; telemetry-api ignored them too).id IN (...)when the caller under-specifies — deferred.Changes
internal/graph/auth_helpers.go— replacerequireRawDataTokenwithhasFullCloudEventAccess+cloudEventRequestAllowed/grantCovers, wired intorequireSubjectOptsByDID.internal/graph/cloud_events_auth_test.go(new) — 22 table-driven cases (wildcard / narrow / specific-ID grants, pluraltypes, full-access bypass, grant-only access, subject mismatch).README.md,MERGER_REVIEW.md— document the two-path model and the gRPC out-of-scope decision.Verification
go build ./...,go vet ./internal/graph/,go test ./internal/graph/all pass.🤖 Generated with Claude Code