Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,6 @@ packages/react-console/gen
/app/.generated/
/app/test/browser/.generated/
/app/test/browser/test-output/*

# Local checkout symlink
/runme
7 changes: 6 additions & 1 deletion app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,19 @@ go run ./ agent --config=${HOME}/.runme-agent/config.dev.yaml serve
# OIDC callback handling should happen in the browser.
clientExchange: true
google:
# Need to set the clientID to validate the audience tokens
# Runtime config applies Google defaults automatically when this block is present.
clientID: "44661292282-bdt3on71kvc489nvi3l37gialolcnk0a.apps.googleusercontent.com"

googleDrive:
clientID: "44661292282-bqhl39ugf2kn7r8vv4f6766jt0a7tom9.apps.googleusercontent.com"
clientSecret: ""

chatkit:
domainKey: "<chatkit-domain-key>"
```

If you need to override the discovery URL, redirect URL, or scopes explicitly, add an `oidc.generic` block alongside `oidc.google`.


* Then in the web in the console you can do.

Expand Down
57 changes: 57 additions & 0 deletions app/assets/about.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>About Runme Web</title>
<style>
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
line-height: 1.5;
color: #111827;
background: #ffffff;
}

main {
max-width: 760px;
margin: 0 auto;
padding: 48px 20px 64px;
}

h1 {
margin-top: 0;
line-height: 1.2;
}
</style>
</head>
<body>
<main>
<h1>About Runme Web</h1>
<p>
Runme Web is a browser-based notebook application for viewing, editing,
and running Runme notebooks. It provides an interface for working with
notebook cells, connecting to execution runners, and integrating with
services such as Google Drive for notebook storage.
</p>
<p>
Privacy Policy:
<a href="http://web.runme.dev/policies/privacypolicy.html">
http://web.runme.dev/policies/privacypolicy.html
</a>
</p>
<p>
Runme:
<a href="https://runme.dev/">https://runme.dev/</a>
</p>
<p>
GitHub:
<a href="https://github.com/runmedev/runme">https://github.com/runmedev/runme</a>
</p>
<p>
Web repository:
<a href="https://github.com/runmedev/web">https://github.com/runmedev/web</a>
</p>
</main>
</body>
</html>
17 changes: 17 additions & 0 deletions app/assets/configs/app-configs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# app-configs.yaml is a file that will be served by the server as a static asset.
# It will be used by the frontend to configure itself.
# This is the configuration for web.runme.dev
oidc:
# OIDC callback handling should happen in the browser.
clientExchange: true

# Use google as the OIDC provider
google:
clientID: "554943104515-bdt3on71kvc489nvi3l37gialolcnk0a.apps.googleusercontent.com"
clientSecret: "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"

googleDrive:
clientID: "554943104515-bdt3on71kvc489nvi3l37gialolcnk0a.apps.googleusercontent.com"

chatkit:
domainKey: "domain_pk_69a4995c6a28819687dae60b7fff88150c50b644747c389a"
41 changes: 41 additions & 0 deletions app/assets/policies/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Runme Web Policies</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
line-height: 1.5;
margin: 0;
color: #111827;
background: #ffffff;
}

main {
max-width: 760px;
margin: 0 auto;
padding: 48px 20px 64px;
}

h1 {
margin-top: 0;
line-height: 1.2;
}
</style>
</head>
<body>
<main>
<h1>Runme Web Policies</h1>
<p>
Privacy Policy:
<a href="/policies/privacypolicy.html">/policies/privacypolicy.html</a>
</p>
<p>
Linux Foundation policies:
<a href="https://lfprojects.org/policies/">https://lfprojects.org/policies/</a>
</p>
</main>
</body>
</html>
97 changes: 97 additions & 0 deletions app/assets/policies/privacypolicy.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Runme Web Privacy Policy</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
line-height: 1.5;
margin: 0;
color: #111827;
background: #ffffff;
}

main {
max-width: 760px;
margin: 0 auto;
padding: 48px 20px 64px;
}

h1,
h2 {
line-height: 1.2;
}

h1 {
margin-top: 0;
}
</style>
</head>
<body>
<main>
<h1>Runme Web Privacy Policy</h1>
<p>Last updated: March 1, 2026</p>

<p>
This Privacy Policy applies to the Runme Web application hosted at
<a href="https://web.runme.dev/">https://web.runme.dev/</a>.
</p>

<h2>Information We Access</h2>
<p>
If you choose to sign in with Google, the application may access Google
account information and tokens needed to authenticate you and enable the
Google features you request. This may include your email address, basic
account identifier information, and OAuth or OpenID Connect tokens.
</p>

<h2>How We Use Google User Data</h2>
<p>
We use Google user data only to authenticate you and to provide the
user-facing functionality you request. We do not use Google user data
for advertising, profiling, sale to third parties, or training general
machine learning or AI models.
</p>

<h2>How We Store Data</h2>
<p>
Runme Web is a static website. We do not operate an application backend
that stores your Google user data. Authentication data used by the site
is processed in your browser and may be stored locally in your browser
storage on your device so the sign-in flow can complete and your session
can continue.
</p>

<h2>How We Share Data</h2>
<p>
We do not sell, transfer, or disclose Google user data to third
parties, except when your browser sends requests directly to Google or
another service you choose to use in order to provide the functionality
you requested.
</p>

<h2>Security</h2>
<p>
We use HTTPS to deliver the application. Because authentication data is
handled in the browser, you should protect access to your device and
sign out or clear site data if you no longer want authentication data
stored locally in your browser.
</p>

<h2>Retention and Deletion</h2>
<p>
We do not retain Google user data on application servers. Data stored in
your browser remains there until it expires, you sign out, or you clear
your browser's local site data.
</p>

<h2>Changes to This Policy</h2>
<p>
If our data handling practices change, we will update this Privacy
Policy on this page.
</p>
</main>
</body>
</html>
2 changes: 1 addition & 1 deletion app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<script type="module" src="./src/main.tsx"></script>
</body>
</html>
10 changes: 8 additions & 2 deletions app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, useEffect, useMemo, useRef } from "react";
import { Helmet } from "react-helmet";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
import Callback from "./routes/callback";
import RunRoute from "./routes/run";
import RunsRoute from "./routes/runs";
Expand Down Expand Up @@ -58,6 +58,7 @@ import {
getConfiguredAgentEndpoint,
getConfiguredDefaultRunnerEndpoint,
} from "./lib/appConfig";
import { APP_ROUTE_PATHS, getAppRouterBasename } from "./lib/appBase";

const queryClient = new QueryClient();

Expand All @@ -73,10 +74,15 @@ export interface AppProps {
}

function AppRouter() {
const basename = getAppRouterBasename();
return (
<BrowserRouter>
<BrowserRouter basename={basename === "/" ? undefined : basename}>
<Routes>
<Route path="/" element={<MainPage />} />
<Route
path={APP_ROUTE_PATHS.indexEntry}
element={<Navigate replace to={APP_ROUTE_PATHS.home} />}
/>
<Route path="/runs" element={<RunsRoute />} />
<Route path="/runs/:runName" element={<RunRoute />} />
<Route path="/runs/:runName/edit" element={<MainPage />} />
Expand Down
21 changes: 12 additions & 9 deletions app/src/auth/oidcConfig.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { googleClientManager } from "../lib/googleClientManager";
import { getOidcCallbackUrl } from "../lib/appBase";

export type OidcConfig = {
discoveryUrl: string;
Expand Down Expand Up @@ -97,14 +98,18 @@ export class OidcConfigManager {
}

setGoogleDefaults(): OidcConfig {
return this.setConfig({
const extraAuthParams = this.sanitizeExtraAuthParams({
access_type: "offline",
prompt: "consent",
});
this.config = {
...this.config,
discoveryUrl: "https://accounts.google.com/.well-known/openid-configuration",
scope: "openid https://www.googleapis.com/auth/userinfo.email",
extraAuthParams: {
access_type: "offline",
prompt: "consent",
},
});
extraAuthParams,
};
this.persistConfig(this.config);
return this.config;
}

private mergeConfig(stored?: StoredOidcConfig): OidcConfig {
Expand All @@ -118,9 +123,7 @@ export class OidcConfigManager {
clientId: sanitizeString(stored?.clientId) ?? "",
clientSecret: sanitizeString(stored?.clientSecret),
scope: sanitizeString(stored?.scope) ?? "",
redirectUri:
sanitizeString(stored?.redirectUri) ??
new URL("/oidc/callback", window.location.origin).toString(),
redirectUri: sanitizeString(stored?.redirectUri) ?? getOidcCallbackUrl(),
extraAuthParams:
mergedExtra && Object.keys(mergedExtra).length > 0
? mergedExtra
Expand Down
18 changes: 3 additions & 15 deletions app/src/components/ChatKit/ChatKitPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
ChatkitStateSchema,
} from "../../protogen/oaiproto/aisre/notebooks_pb.js";
import { useAgentEndpointSnapshot } from "../../lib/agentEndpointManager";
import { getConfiguredChatKitDomainKey } from "../../lib/appConfig";

class UserNotLoggedInError extends Error {
constructor(message = "You must log in to use runme chat.") {
Expand All @@ -27,20 +28,6 @@ class UserNotLoggedInError extends Error {
}
}

const CHATKIT_DOMAIN_KEY = (() => {
const envValue = import.meta.env.VITE_CHATKIT_DOMAIN_KEY;
if (envValue) {
return envValue;
}
if (
typeof window !== "undefined" &&
window.location.hostname === "localhost"
) {
return "domain_pk_localhost_dev";
}
return "domain_pk_68f8054e7da081908cc1972e9167ec270895bf04413e753b";
})();

const CHATKIT_GREETING = "How can runme help you today?";

const CHATKIT_PLACEHOLDER =
Expand Down Expand Up @@ -227,6 +214,7 @@ const useAuthorizedFetch = (

function ChatKitPanel() {
const [showLoginPrompt, setShowLoginPrompt] = useState(false);
const chatkitDomainKey = getConfiguredChatKitDomainKey();
const agentEndpoint = useAgentEndpointSnapshot();
const { getChatkitState, setChatkitState } = useCell();
const { getNotebookData, useNotebookSnapshot } = useNotebookContext();
Expand Down Expand Up @@ -330,7 +318,7 @@ function ChatKitPanel() {
const chatkit = useChatKit({
api: {
url: chatkitApiUrl,
domainKey: CHATKIT_DOMAIN_KEY,
domainKey: chatkitDomainKey,
fetch: authorizedFetch,
},
theme: {
Expand Down
5 changes: 3 additions & 2 deletions app/src/components/NotFound.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Container, Heading, Link, Text } from "@radix-ui/themes";
import { Link as RouterLink } from "react-router-dom";

const NotFound = () => {
return (
Expand All @@ -14,8 +15,8 @@ const NotFound = () => {
</Text>
<Text as="p" mt="4">
Click{" "}
<Link href="/" underline="always">
here
<Link asChild underline="always">
<RouterLink to="/">here</RouterLink>
</Link>{" "}
to go back home.
</Text>
Expand Down
Loading
Loading