Skip to content

Inside CORE

FORGE is a CORE component. It has no domain, no DNS record, no OAuth client, no login screen, no session store and no sign-out. There is no forge.runink.org. It appears as the FORGE category in CORE’s console rail, and it never needs a route, origin or record of its own.

The path

  1. The browser is at https://core.runink.org/forge/….
  2. CORE’s console strips /forge and reverse-proxies the request to the FORGE service. That service serves the Flutter bundle and gRPC-web at /.
  3. The bundle is built with --base-href /forge/. The studio therefore resolves its gRPC-web calls relative to the page, as <origin>/forge/<service>/<method>.

Because of the base href, opening the backend’s own / directly cannot load the bundle’s assets. Locally, use forge dev proxy.

Identity

On every request, CORE’s proxy removes any inbound X-Core-Identity and attaches a fresh assertion, made with github.com/org-runink/security/coreidentity. The assertion is an HMAC-SHA256 over {sub: email, aud: "forge", iat} with a maximum age of two minutes, keyed with CORE_FORGE_IDENTITY_KEY. The key is shared only between CORE’s console and FORGE.

Every RPC except gRPC reflection passes through FORGE’s auth interceptors, which verify the assertion. gRPC-web headers reach the interceptor as metadata. A stream is checked when it opens, so the two-minute limit does not cut a stream that started with a fresh assertion.

CaseAnswer
Valid assertion, FORGE_OWNER_EMAIL unsetAdmitted. CORE’s sign-in is the only gate.
Valid assertion, address listed in FORGE_OWNER_EMAILAdmitted
Valid assertion, FORGE_OWNER_EMAIL set but the address not in itPermissionDenied: this account is not on this forge instance's allowlist (FORGE_OWNER_EMAIL)
Missing, malformed, expired, future-dated, wrong-audience, badly signed or duplicated assertionUnauthenticated: FORGE is opened from CORE — sign in to CORE
CORE_FORGE_IDENTITY_KEY unset, not base64, or shorter than 32 bytesFailedPrecondition naming the variable, on every RPC (fail closed)

Two assertions on one request mean a proxy failed to strip the inbound one. FORGE refuses rather than guess which one CORE wrote. A refusal is logged as the coreidentity error sentinel only: the header value is a bearer credential and never reaches a log or a reply.

The verified email is the actor. IdentityService.WhoAmI returns it, the chat store is keyed by it, and the audit records it.

What the person sees

When WhoAmI fails, the studio shows one plain line and an Open CORE button:

  • FORGE is opened from CORE — sign in to CORE.
  • Your CORE account is not on this FORGE's allowlist.
  • FORGE could not check who you are: …

Any later call that answers Unauthenticated reads as CORE did not vouch for you — sign in to CORE again., because it means CORE’s session ended. Signing out is done from CORE’s rail footer.

How CORE shows FORGE

  • The rail is FORGE’s chat history: New chat (/forge/?chat=new), then the recent chats, newest first. CORE reads the list through the same-origin /forge/ proxy, using runink.ui.chat.v1.ChatService/ListChats on the CORE session.
  • The page header names the chat. The studio reports what it shows with a same-origin postMessage of {"type":"forge.chat","id","title","project"}, which carries ids and display text only. CORE accepts it only from its own origin and from the studio iframe’s own window.
  • CORE files no briefs. Filing is FORGE’s alone, through ApproveChat. CORE’s coding agents consume the forge-labelled issues, and FORGE is their only producer.

Network

FORGE’s on-host manifest (merged in core) creates the forge-system namespace, a Service, and NetworkPolicies that admit only CORE’s console. The image listens on :: because the platform’s pod network is IPv6 single-stack.

Sources

grpc/cmd/auth_interceptor.go; grpc/internal/auth/identity.go; flutter/lib/core/auth/core_gate_screen.dart; flutter/lib/core/grpc/channel_provider.dart (forgeErrorText); flutter/lib/features/forge/core_frame_web.dart; CLAUDE.md (“Authentication — CORE vouches”); core’s CLAUDE.md (the FORGE rail and forgeproxy.go).