Skip to content

BE-714: Gate the actor-ID header behind a service credential - #9233

Open
TimDiekmann wants to merge 4 commits into
t/be-760-verify-kratos-sessions-in-the-graph-apifrom
t/be-714-define-node-api-authentication-to-the-graph
Open

BE-714: Gate the actor-ID header behind a service credential#9233
TimDiekmann wants to merge 4 commits into
t/be-760-verify-kratos-sessions-in-the-graph-apifrom
t/be-714-define-node-api-authentication-to-the-graph

Conversation

@TimDiekmann

Copy link
Copy Markdown
Member

🌟 What is the purpose of this PR?

Closes the last unauthenticated path into the Graph REST API: the X-Authenticated-User-Actor-Id header is only honored next to a service secret. Internal services (Node API, Temporal workers) authenticate themselves before naming the actor they act for, and the bootstrap routes require the same secret instead of being reachable by anyone on the network.

🔗 Related links

🚫 Blocked by

🔍 What does this change?

  • AuthenticationProvider returns ControlFlow<Authentication>: Continue(()) means the request carries no credential the provider handles, Break(Verified | Rejected) is terminal. Chaining is the ? operator, so a rejected credential structurally cannot fall through to another provider
  • Authentication::Verified carries the authorization crate's AuthenticatedActor — Kratos verifies to a typed Id, service delegation passes the claimed actor through as Uuid
  • delegation::ServiceDelegationProvider recognizes the pair of X-HASH-Service-Secret and the actor-ID header as one credential. The secret is compared in constant time. An actor-ID header without the secret is rejected, never ignored
  • the bare actor-ID header fallback in resolve_request_actor is deleted; the new rejections log at warn level, since only internal services send these credentials and a mismatch is a deployment problem
  • bootstrap routes (/policies/seed, /actors/machine/identifier/system/{identifier}) require the service secret and lose their unauthenticated allowlist entries
  • the server requires a non-empty HASH_GRAPH_SERVICE_SECRET to start (parse-optional so server --healthcheck works without it), and an empty configured secret never matches — a set-but-empty variable cannot silently disable the credential
  • bootstrap routes admit only requests carrying no credential at all: an actively rejected credential (malformed actor header, stale session cookie) stays rejected there too
  • the Node API and both Temporal workers send the secret as an axios default header from the same variable; the config structs mask it (and the OpenAI key) in Debug output
  • compose sets the secret on the graph service and all four senders; the httpyac suite injects it via a .httpyac.config.js hook, and service-delegation.http pins the rejection paths end-to-end
  • drive-by: hide_env_values on the five sensitive clap env args (Postgres password ×2, OpenAI key, Mailchimp key, Sentry DSN) — --help no longer prints their values

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • does not modify any publishable blocks or libraries, or modifications do not need publishing

📜 Does this require a change to the docs?

The changes in this PR:

  • are internal and do not require a docs change

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

  • Deploy order matters: the senders roll out first (the current Graph ignores the extra header), then the Graph — it refuses to start without the secret. The secret must exist in Secrets Manager and the task definitions before rollout; that is the next internal-infra PR.
  • One static secret shared by all senders; rotating it requires restarting every consumer in lockstep. A dual-secret rotation window is tracked in BE-763 (internal).
  • Delegated actors are passed through as claimed rather than validated against the principal store: the secret authenticates the sender, the Node API legitimately delegates to the public actor for anonymous requests, and a per-request store lookup would tax the hottest path before the BE-755 (internal) cache exists.
  • The admin server keeps its bare actor-ID header middleware (behind Cloudflare Access) until BE-761 (internal) moves it onto the shared pipeline.
  • The custom header is transitional by design and superseded by Hydra client_credentials (BE-728 (internal)).

🐾 Next steps

  • provision the secret in staging/production (internal-infra)
  • Cloudflare Access JWTs as a provider and admin-server unification (BE-761) (internal)
  • OAuth2 client_credentials for service identity (BE-728) (internal)

🛡 What tests cover this?

  • delegation.rs unit tests: the full header matrix — pair verifies, wrong secret, actor header without secret (the no-fallback case), secret without actor, malformed actor UUID
  • provider.rs chain tests: falls through on Continue, stops at the first Verified or Rejected
  • middleware tests: bootstrap routes with/without/with-wrong secret, bare actor headers, verified passthrough
  • service-delegation.http end-to-end rejection paths with client-safe message asserts; the entire HTTP suite now runs through the delegation path via the injected secret

❓ How to test this?

  1. Start the external services and the Graph (yarn start:graph or cargo run --bin hash-graph --all-features -- server)
  2. curl -i http://127.0.0.1:4000/actors/machine/identifier/system/h -H "X-HASH-Service-Secret: hash-svc-local-dev-secret" → 200; without the header → 401
  3. Any request with X-Authenticated-User-Actor-Id but without the secret → 401 the actor-ID header requires the service credential
  4. Full suite: cd tests/graph/http && sh test.sh

🐒 Demo

N/A — backend authentication path; see the httpyac suite output for the wire-level flow.

@TimDiekmann TimDiekmann self-assigned this Aug 17, 2026
@vercel

vercel Bot commented Aug 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview Aug 17, 2026 12:11pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Aug 17, 2026 12:11pm
petrinaut Skipped Skipped Aug 17, 2026 12:11pm

@github-actions github-actions Bot added area/deps Relates to third-party dependencies (area) area/apps > hash* Affects HASH (a `hash-*` app) area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > backend Owned by the @backend team area/tests New or updated tests area/apps area/apps > hash-graph labels Aug 17, 2026
@TimDiekmann
TimDiekmann deployed to pull-request August 17, 2026 11:26 — with GitHub Actions Active
@TimDiekmann
TimDiekmann deployed to pull-request August 17, 2026 11:26 — with GitHub Actions Active
@codecov

codecov Bot commented Aug 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.15738% with 20 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.92%. Comparing base (0eb0f78) to head (99c31d8).

Files with missing lines Patch % Lines
libs/@local/graph/api/src/rest/mod.rs 0.00% 10 Missing ⚠️
libs/@local/graph/authentication/src/request.rs 80.95% 3 Missing and 1 partial ⚠️
libs/@local/graph/authentication/src/delegation.rs 98.51% 1 Missing and 1 partial ⚠️
libs/@local/graph/authentication/src/kratos.rs 97.18% 0 Missing and 2 partials ⚠️
libs/@local/graph/authentication/src/provider.rs 97.22% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@                                 Coverage Diff                                  @@
##           t/be-760-verify-kratos-sessions-in-the-graph-api    #9233      +/-   ##
====================================================================================
+ Coverage                                             59.84%   59.92%   +0.08%     
====================================================================================
  Files                                                  1425     1426       +1     
  Lines                                                139512   139853     +341     
  Branches                                               6570     6579       +9     
====================================================================================
+ Hits                                                  83484    83811     +327     
- Misses                                                54958    54969      +11     
- Partials                                               1070     1073       +3     
Flag Coverage Δ
apps.hash-ai-worker-ts 1.99% <ø> (ø)
apps.hash-api 14.00% <ø> (ø)
local.hash-backend-utils 3.27% <ø> (ø)
local.hash-graph-sdk 10.02% <ø> (ø)
local.hash-isomorphic-utils 12.22% <ø> (ø)
rust.hash-graph-api 12.34% <90.29%> (+1.33%) ⬆️
rust.hash-graph-authentication 93.47% <96.77%> (+1.66%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread apps/hash-graph/src/subcommand/server.rs
@codspeed-hq

codspeed-hq Bot commented Aug 17, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 98 untouched benchmarks


Comparing t/be-714-define-node-api-authentication-to-the-graph (99c31d8) with t/be-760-verify-kratos-sessions-in-the-graph-api (0eb0f78)

Open in CodSpeed

@vercel
vercel Bot temporarily deployed to Preview – petrinaut August 17, 2026 11:39 Inactive
@TimDiekmann
TimDiekmann marked this pull request as ready for review August 17, 2026 11:42
Copilot AI balanced review requested due to automatic review settings August 17, 2026 11:42
@cursor

cursor Bot commented Aug 17, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Changes core Graph REST authentication, bootstrap provisioning, and deploy ordering (senders must carry the secret before the Graph enforces it); misconfiguration can block startup or lock out internal services.

Overview
Closes the unauthenticated X-Authenticated-User-Actor-Id path by requiring internal callers to present X-HASH-Service-Secret alongside that header. A new ServiceDelegationProvider treats the pair as one credential (constant-time secret check); the bare actor-ID fallback in credential resolution is removed, and invalid delegation errors log at warn level.

Bootstrap routes (/policies/seed, system machine identifier lookup) now require the service secret instead of being reachable without credentials; the REST middleware still allows them through without an actor when the secret is valid.

The Graph server refuses to start without a non-empty HASH_GRAPH_SERVICE_SECRET (optional at CLI parse so --healthcheck still works). Kratos session auth is chained with delegation via ControlFlow-based providers so a rejected credential cannot fall through. Node API / Graph axios clients and Compose services send the secret; httpYac injects it suite-wide with new service-delegation.http coverage.

Also masks sensitive env values in CLI Debug / --help for Postgres password, OpenAI key, Mailchimp, and Sentry DSN.

Reviewed by Cursor Bugbot for commit 99c31d8. Bugbot is set up for automated code reviews on this repo. Configure here.

@TimDiekmann
TimDiekmann force-pushed the t/be-714-define-node-api-authentication-to-the-graph branch from 65ebe47 to 3654b9c Compare August 17, 2026 11:43
@TimDiekmann
TimDiekmann deployed to pull-request August 17, 2026 11:44 — with GitHub Actions Active
@TimDiekmann
TimDiekmann deployed to pull-request August 17, 2026 11:44 — with GitHub Actions Active

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.

Pull request overview

Gates Graph actor delegation and bootstrap routes behind a shared service credential.

Changes:

  • Adds composable Kratos and service-delegation authentication providers.
  • Wires the credential through Graph clients, server configuration, and Compose.
  • Adds delegation tests and masks sensitive CLI environment values.

Reviewed changes

Copilot reviewed 23 out of 24 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
.env Defines the local service secret.
Cargo.toml Adds the constant-time comparison dependency.
Cargo.lock Records generated dependency updates.
apps/hash-graph/Cargo.toml Adds debug-derivation support.
apps/hash-graph/src/subcommand/admin_server.rs Hides the Mailchimp key in help.
apps/hash-graph/src/subcommand/server.rs Validates and masks the service secret.
infra/compose/compose.yml Distributes the secret to Graph services.
libs/@local/graph/api/src/rest/auth.rs Enforces authentication and bootstrap gating.
libs/@local/graph/api/src/rest/mod.rs Wires the provider chain into REST.
libs/@local/graph/authentication/Cargo.toml Adds subtle.
libs/@local/graph/authentication/src/actor.rs Shares a test actor resolver.
libs/@local/graph/authentication/src/delegation.rs Implements service delegation.
libs/@local/graph/authentication/src/kratos.rs Adapts Kratos to provider chaining.
libs/@local/graph/authentication/src/lib.rs Exports delegation support.
libs/@local/graph/authentication/src/provider.rs Introduces terminal provider chaining.
libs/@local/graph/authentication/src/request.rs Removes bare actor-header fallback.
libs/@local/graph/migrations/src/bin/cli/subcommand/mod.rs Hides database passwords in help.
libs/@local/graph/postgres-store/src/store/config.rs Hides database passwords in help.
libs/@local/hash-backend-utils/src/create-graph-client.ts Sends the service credential by default.
libs/@local/telemetry/src/traces/sentry.rs Hides Sentry DSN values in help.
tests/graph/http/.httpyac.config.js Injects the secret into HTTP tests.
tests/graph/http/test.sh Runs delegation integration tests.
tests/graph/http/tests/hashql.http Preserves the no-credentials test case.
tests/graph/http/tests/service-delegation.http Covers delegation rejection paths.

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

Comment thread infra/compose/compose.yml
Comment thread tests/graph/http/.httpyac.config.js
Comment thread tests/graph/http/tests/service-delegation.http Outdated
Comment thread libs/@local/graph/api/src/rest/auth.rs Outdated

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.

Pull request overview

Copilot reviewed 23 out of 24 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

tests/graph/http/.httpyac.config.js:11

  • This suite-wide hook adds the service secret to every HTTP request, including requests to Kratos (kratos-session.http:44,72,83) and the type fetcher (type-fetcher.http:9,27). That forwards a sensitive Graph credential to unrelated services. Scope the injection and <omit> handling to the Graph REST origin (127.0.0.1:4000) only.
    api.hooks.onRequest.addHook("serviceSecret", (request) => {
      request.headers = {
        "X-HASH-Service-Secret":
          process.env.HASH_GRAPH_SERVICE_SECRET ?? "hash-svc-local-dev-secret",
        ...request.headers,
      };

libs/@local/graph/authentication/src/request.rs:131

  • Making providers the only credential path invalidates the current OpenAPI source annotations: operations still advertise X-Authenticated-User-Actor-Id alone (for example api/src/rest/property_type.rs:141 and principal.rs:206), while bootstrap operations advertise no service-secret header. Those documented requests now receive 401. Update the utoipa authentication/header contract for both delegated and bootstrap calls so generated clients expose the required credential.
/// The provider is the only credential path: a request whose credential is rejected fails, and a
/// request without a recognized credential fails as [`MissingCredentials`]. Chain providers as
/// pairs, nested for more than two, to accept several credential kinds.

Comment thread libs/@local/graph/api/src/rest/auth.rs Outdated
Copilot AI review requested due to automatic review settings August 17, 2026 11:57
@vercel
vercel Bot temporarily deployed to Preview – petrinaut August 17, 2026 11:57 Inactive
@TimDiekmann
TimDiekmann deployed to pull-request August 17, 2026 11:58 — with GitHub Actions Active
@TimDiekmann
TimDiekmann deployed to pull-request August 17, 2026 11:58 — with GitHub Actions Active

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.

Pull request overview

Copilot reviewed 23 out of 24 changed files in this pull request and generated no new comments.

Suppressed comments (1)

infra/compose/compose.yml:623

  • The Compose topology is documented as the starting point for self-hosted deployments (README.md:182) and publishes Graph on all host interfaces (compose.yml:629-630). Falling back to this repository-known credential means a deployment that does not override the variable accepts a secret any client knows, allowing it to delegate as an arbitrary actor. Require an explicitly supplied production secret across Graph and every sender, while keeping the local-development value in a development-only configuration.
      HASH_GRAPH_SERVICE_SECRET: "${HASH_GRAPH_SERVICE_SECRET:-hash-svc-local-dev-secret}"

Copilot AI review requested due to automatic review settings August 17, 2026 12:02
@vercel
vercel Bot temporarily deployed to Preview – petrinaut August 17, 2026 12:02 Inactive
@TimDiekmann
TimDiekmann deployed to pull-request August 17, 2026 12:04 — with GitHub Actions Active
@TimDiekmann
TimDiekmann deployed to pull-request August 17, 2026 12:04 — with GitHub Actions Active

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.

Pull request overview

Copilot reviewed 24 out of 25 changed files in this pull request and generated no new comments.

Suppressed comments (2)

libs/@local/graph/api/src/rest/auth.rs:100

  • This newly requires a service secret on the two bootstrap endpoints, but their source OpenAPI annotations still advertise no credential/header or 401 response (rest/permissions.rs:314-322 and rest/principal.rs:169-180). Consumers generated from that contract will call these routes without the new header and receive 401. Update both source annotations to describe the service-secret requirement and unauthenticated response; likewise model the service-secret + actor-ID pair for the existing actor-header annotations rather than editing generated OpenAPI output.
    let bootstrap = is_bootstrap_route(request.uri().path());
    if bootstrap && !presents_service_secret(request.headers(), &service_secret) {
        return rejection(&AuthenticationError::MissingServiceSecret).into_response();

libs/@local/graph/api/src/rest/auth.rs:101

  • A bootstrap request with an X-HASH-Service-Secret header that is present but incorrect also enters this branch, so it is reported as MissingServiceSecret ("request requires" a credential) rather than InvalidServiceSecret. Because this returns before resolve_request_actor, it also bypasses the warn-level mismatch logging used for stale deployments. Distinguish an absent header from a mismatched value here, return InvalidServiceSecret for the latter, and emit the same warn-level signal.
    if bootstrap && !presents_service_secret(request.headers(), &service_secret) {
        return rejection(&AuthenticationError::MissingServiceSecret).into_response();

@github-actions

Copy link
Copy Markdown
Contributor

Benchmark results

@rust/hash-graph-benches – Integrations

policy_resolution_large

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2002 $$20.0 \mathrm{ms} \pm 166 \mathrm{μs}\left({\color{gray}2.00 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.43 \mathrm{ms} \pm 15.5 \mathrm{μs}\left({\color{red}11.7 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1002 $$8.96 \mathrm{ms} \pm 56.7 \mathrm{μs}\left({\color{gray}-1.755 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$28.7 \mathrm{ms} \pm 226 \mathrm{μs}\left({\color{gray}4.81 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$9.27 \mathrm{ms} \pm 78.0 \mathrm{μs}\left({\color{gray}2.41 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1527 $$15.8 \mathrm{ms} \pm 133 \mathrm{μs}\left({\color{lightgreen}-6.132 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$20.0 \mathrm{ms} \pm 126 \mathrm{μs}\left({\color{lightgreen}-8.827 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.60 \mathrm{ms} \pm 12.7 \mathrm{μs}\left({\color{gray}-1.107 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$9.43 \mathrm{ms} \pm 70.8 \mathrm{μs}\left({\color{lightgreen}-10.656 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$2.41 \mathrm{ms} \pm 12.2 \mathrm{μs}\left({\color{gray}0.769 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$1.95 \mathrm{ms} \pm 10.3 \mathrm{μs}\left({\color{lightgreen}-6.637 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 52 $$2.16 \mathrm{ms} \pm 10.6 \mathrm{μs}\left({\color{gray}-3.476 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$3.35 \mathrm{ms} \pm 18.0 \mathrm{μs}\left({\color{lightgreen}-7.836 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$2.27 \mathrm{ms} \pm 11.3 \mathrm{μs}\left({\color{gray}-4.907 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 108 $$2.65 \mathrm{ms} \pm 16.0 \mathrm{μs}\left({\color{lightgreen}-7.670 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$3.04 \mathrm{ms} \pm 19.8 \mathrm{μs}\left({\color{red}7.02 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.25 \mathrm{ms} \pm 13.3 \mathrm{μs}\left({\color{gray}2.62 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$2.56 \mathrm{ms} \pm 17.4 \mathrm{μs}\left({\color{gray}-3.267 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$1.72 \mathrm{ms} \pm 10.2 \mathrm{μs}\left({\color{gray}0.138 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$1.79 \mathrm{ms} \pm 71.1 \mathrm{μs}\left({\color{red}10.0 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 2 $$1.68 \mathrm{ms} \pm 9.78 \mathrm{μs}\left({\color{gray}-3.943 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$1.98 \mathrm{ms} \pm 13.2 \mathrm{μs}\left({\color{gray}-2.462 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$1.74 \mathrm{ms} \pm 19.2 \mathrm{μs}\left({\color{gray}-4.633 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$1.88 \mathrm{ms} \pm 15.6 \mathrm{μs}\left({\color{gray}-1.082 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$2.00 \mathrm{ms} \pm 12.7 \mathrm{μs}\left({\color{gray}-0.261 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$1.81 \mathrm{ms} \pm 10.4 \mathrm{μs}\left({\color{gray}-0.034 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 26 $$1.93 \mathrm{ms} \pm 16.0 \mathrm{μs}\left({\color{lightgreen}-10.127 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$2.18 \mathrm{ms} \pm 13.8 \mathrm{μs}\left({\color{gray}-1.288 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$1.95 \mathrm{ms} \pm 11.3 \mathrm{μs}\left({\color{gray}1.86 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 27 $$2.18 \mathrm{ms} \pm 14.8 \mathrm{μs}\left({\color{gray}2.39 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$2.14 \mathrm{ms} \pm 14.5 \mathrm{μs}\left({\color{gray}-1.356 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$1.90 \mathrm{ms} \pm 12.2 \mathrm{μs}\left({\color{lightgreen}-6.324 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$2.12 \mathrm{ms} \pm 10.4 \mathrm{μs}\left({\color{gray}0.683 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$30.2 \mathrm{ms} \pm 188 \mathrm{μs}\left({\color{gray}-2.511 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$24.3 \mathrm{ms} \pm 131 \mathrm{μs}\left({\color{gray}-4.529 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$26.7 \mathrm{ms} \pm 163 \mathrm{μs}\left({\color{gray}1.07 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$23.2 \mathrm{ms} \pm 115 \mathrm{μs}\left({\color{lightgreen}-5.244 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$32.4 \mathrm{ms} \pm 148 \mathrm{μs}\left({\color{gray}0.053 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$36.0 \mathrm{ms} \pm 197 \mathrm{μs}\left({\color{gray}-3.203 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$28.4 \mathrm{ms} \pm 137 \mathrm{μs}\left({\color{lightgreen}-7.494 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$62.0 \mathrm{ms} \pm 514 \mathrm{μs}\left({\color{gray}-4.989 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$24.5 \mathrm{ms} \pm 140 \mathrm{μs}\left({\color{lightgreen}-40.456 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$181 \mathrm{ms} \pm 836 \mathrm{μs}\left({\color{gray}-3.716 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$7.88 \mathrm{ms} \pm 34.4 \mathrm{μs}\left({\color{gray}-4.878 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$7.90 \mathrm{ms} \pm 40.6 \mathrm{μs}\left({\color{gray}-3.548 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$8.00 \mathrm{ms} \pm 47.7 \mathrm{μs}\left({\color{lightgreen}-5.765 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$7.89 \mathrm{ms} \pm 32.1 \mathrm{μs}\left({\color{gray}-3.992 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$8.02 \mathrm{ms} \pm 32.9 \mathrm{μs}\left({\color{gray}-2.979 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$7.87 \mathrm{ms} \pm 58.9 \mathrm{μs}\left({\color{gray}-0.303 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$7.98 \mathrm{ms} \pm 30.3 \mathrm{μs}\left({\color{gray}-1.905 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$8.10 \mathrm{ms} \pm 43.5 \mathrm{μs}\left({\color{gray}-1.861 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$8.05 \mathrm{ms} \pm 46.1 \mathrm{μs}\left({\color{gray}-1.527 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$8.32 \mathrm{ms} \pm 51.3 \mathrm{μs}\left({\color{gray}2.45 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity

Function Value Mean Flame graphs
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1 $$8.37 \mathrm{ms} \pm 176 \mathrm{μs}\left({\color{gray}-2.204 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$8.41 \mathrm{ms} \pm 202 \mathrm{μs}\left({\color{gray}1.79 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$8.19 \mathrm{ms} \pm 38.3 \mathrm{μs}\left({\color{gray}-2.243 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$8.25 \mathrm{ms} \pm 48.2 \mathrm{μs}\left({\color{gray}-4.527 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$8.29 \mathrm{ms} \pm 38.9 \mathrm{μs}\left({\color{lightgreen}-5.531 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$7.95 \mathrm{ms} \pm 30.6 \mathrm{μs}\left({\color{lightgreen}-11.111 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$8.02 \mathrm{ms} \pm 34.0 \mathrm{μs}\left({\color{lightgreen}-7.271 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$8.05 \mathrm{ms} \pm 32.3 \mathrm{μs}\left({\color{lightgreen}-7.622 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$8.11 \mathrm{ms} \pm 35.9 \mathrm{μs}\left({\color{lightgreen}-5.381 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity_type

Function Value Mean Flame graphs
get_entity_type_by_id Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba $$5.98 \mathrm{ms} \pm 23.6 \mathrm{μs}\left({\color{gray}-4.310 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$40.5 \mathrm{ms} \pm 345 \mathrm{μs}\left({\color{lightgreen}-18.371 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$86.0 \mathrm{ms} \pm 453 \mathrm{μs}\left({\color{gray}-2.816 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$46.4 \mathrm{ms} \pm 347 \mathrm{μs}\left({\color{lightgreen}-14.956 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$56.6 \mathrm{ms} \pm 410 \mathrm{μs}\left({\color{lightgreen}-8.224 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$61.6 \mathrm{ms} \pm 328 \mathrm{μs}\left({\color{lightgreen}-12.176 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$68.4 \mathrm{ms} \pm 404 \mathrm{μs}\left({\color{lightgreen}-7.274 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$30.9 \mathrm{ms} \pm 214 \mathrm{μs}\left({\color{lightgreen}-5.251 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$50.6 \mathrm{ms} \pm 262 \mathrm{μs}\left({\color{lightgreen}-10.955 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$35.9 \mathrm{ms} \pm 229 \mathrm{μs}\left({\color{lightgreen}-7.239 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$44.1 \mathrm{ms} \pm 262 \mathrm{μs}\left({\color{gray}-4.866 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$44.3 \mathrm{ms} \pm 276 \mathrm{μs}\left({\color{gray}-3.797 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$44.5 \mathrm{ms} \pm 211 \mathrm{μs}\left({\color{lightgreen}-5.122 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$79.0 \mathrm{ms} \pm 358 \mathrm{μs}\left({\color{gray}-0.656 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$87.9 \mathrm{ms} \pm 301 \mathrm{μs}\left({\color{gray}-2.022 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$16.4 \mathrm{ms} \pm 106 \mathrm{μs}\left({\color{red}21.7 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$374 \mathrm{ms} \pm 1.54 \mathrm{ms}\left({\color{gray}-3.600 \mathrm{\%}}\right) $$ Flame Graph

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

Labels

area/apps > hash* Affects HASH (a `hash-*` app) area/apps > hash-graph area/apps area/deps Relates to third-party dependencies (area) area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) area/tests New or updated tests type/eng > backend Owned by the @backend team

Development

Successfully merging this pull request may close these issues.

2 participants