Skip to content

Commit cbe3276

Browse files
committed
Use VITE_DEV_TOKEN env var for dev auth token; add pre-commit hook to block JWT commits
1 parent 56b7944 commit cbe3276

6 files changed

Lines changed: 121 additions & 9 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ apps/nar-browser/lib
1515
__pycache__
1616
.ipynb_checkpoints
1717

18+
# secrets
19+
apps/nar-v3/.env.local
20+
1821
# other
1922
*.log
2023
*.DS_Store

CLAUDE.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Repository layout
6+
7+
All application code lives in `apps/nar-v3/`. The repo root contains only CI/CD configuration (`.gitlab-ci.yml`, `.github/workflows/`).
8+
9+
## Commands
10+
11+
All commands run from `apps/nar-v3/`:
12+
13+
```bash
14+
npm run dev # start Vite dev server
15+
npm run build # production build
16+
npm run lint # ESLint (0 warnings allowed)
17+
npm test # run all tests (requires EBRAINS KG connectivity for "KG" tests)
18+
npm run testci # run tests that don't require KG connectivity (CI-safe)
19+
npm run coverage # test coverage
20+
```
21+
22+
Run a single test file or filter by name:
23+
```bash
24+
npx vitest __tests__/utility.test.js
25+
npx vitest --grep "test name pattern"
26+
```
27+
28+
## Authentication in development
29+
30+
The app uses Keycloak/EBRAINS IAM OAuth. To authenticate in dev mode, copy `apps/nar-v3/.env.local.example` to `apps/nar-v3/.env.local` and paste a valid EBRAINS IAM token as `VITE_DEV_TOKEN`. The dev server will use it automatically — no edits to `main.jsx` needed. `.env.local` is gitignored. Tests that require live KG access have "KG" in their name and are skipped by `testci`.
31+
32+
## Architecture
33+
34+
The app is a React SPA that provides a browsable interface to neural activity datasets stored in the **EBRAINS Knowledge Graph (KG)**. Users can explore datasets, subjects, slices, patched cells, and electrophysiology recordings.
35+
36+
### Data flow
37+
38+
```
39+
React Router v6 loader
40+
→ datastore.js (fetch + in-memory cache)
41+
→ KG Core API v3 (https://core.kg.ebrains.eu/v3)
42+
→ openMINDS-formatted JSON-LD responses
43+
```
44+
45+
Route loaders (in `src/routes/`) fetch data before rendering. `datastore.js` wraps all KG API calls with caching. `queries.js` and `queryLibrary.js` build the KG query payloads.
46+
47+
### Graph database with hierarchical views
48+
49+
The underlying data is a graph database (the EBRAINS KG). The current dataset views impose a particular hierarchical traversal of that graph, but this is just one perspective — future views may root themselves at different nodes (e.g. a recording-centric or subject-centric view).
50+
51+
For patch clamp, the graph path from dataset to recordings looks like:
52+
53+
```
54+
Dataset
55+
└── StudiedSpecimen (Subject)
56+
└── StudiedState
57+
└── SlicePreparation → Slice(s)
58+
└── CellPatching → PatchedCell(s)
59+
└── RecordingActivity / StimulationActivity
60+
└── DataFile(s)
61+
```
62+
63+
For other electrophysiology modalities, there may be one or more intermediate Activities whose output is another StudiedState (rather than a final recording), before eventually reaching the RecordingActivity. The graph is not strictly a tree.
64+
65+
Each level of this hierarchy has a corresponding card component in `src/components/`.
66+
67+
### Auth and curator access
68+
69+
`auth.js` handles Keycloak login and checks whether the user has curator permissions. Curators see `IN_PROGRESS` stage data; regular users see only `RELEASED` data. This stage flag flows through `datastore.js` into every KG query.
70+
71+
### Key source files
72+
73+
- `src/main.jsx` — app entry, Keycloak init, dev token
74+
- `src/routes/` — React Router route components with loaders
75+
- `src/datastore.js` — KG API wrapper with caching
76+
- `src/queries.js` / `src/queryLibrary.js` — KG query construction
77+
- `src/auth.js` — Keycloak authentication
78+
- `src/components/` — display components (one per hierarchy level)
79+
80+
## Docker & deployment
81+
82+
Two-stage Docker build: Node 20 for `npm run build`, then Nginx alpine to serve the static output on port 8080 as a non-root user. GitLab CI pushes `:prod` (main branch) or `:dev` (development branch) to `docker-registry.ebrains.eu/neuralactivity/nar-app-v3`.

apps/nar-v3/.env.local.example

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copy this file to .env.local and paste your EBRAINS IAM token below.
2+
# .env.local is gitignored — never commit your token.
3+
#
4+
# Get a token by logging in to https://iam.ebrains.eu and copying the
5+
# access token, or by running the dev server and grabbing it from the
6+
# browser's local storage after a successful login.
7+
VITE_DEV_TOKEN=

apps/nar-v3/src/main.jsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,11 @@ function renderApp(auth) {
126126
);
127127
}
128128

129-
window.addEventListener("DOMContentLoaded", () => initAuth(renderApp));
130-
131-
132-
// -- for development, comment out the previous line and uncomment the following ones
133-
134-
// const auth = {
135-
// token: "<paste token here>"
136-
// };
137-
// window.addEventListener('DOMContentLoaded', () => renderApp(auth));
129+
// In development, if VITE_DEV_TOKEN is set in .env.local, use it directly.
130+
// Otherwise fall through to the normal Keycloak login flow.
131+
// See .env.local.example for setup instructions.
132+
if (import.meta.env.DEV && import.meta.env.VITE_DEV_TOKEN) {
133+
window.addEventListener("DOMContentLoaded", () => renderApp({ token: import.meta.env.VITE_DEV_TOKEN }));
134+
} else {
135+
window.addEventListener("DOMContentLoaded", () => initAuth(renderApp));
136+
}

scripts/install-hooks.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/sh
2+
# Install git hooks from the scripts/ directory.
3+
# Run once after cloning: sh scripts/install-hooks.sh
4+
5+
REPO_ROOT="$(git rev-parse --show-toplevel)"
6+
7+
cp "$REPO_ROOT/scripts/pre-commit" "$REPO_ROOT/.git/hooks/pre-commit"
8+
chmod +x "$REPO_ROOT/.git/hooks/pre-commit"
9+
10+
echo "Installed pre-commit hook."

scripts/pre-commit

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/sh
2+
# Pre-commit hook: block commits that contain JWT tokens.
3+
# Install by running: scripts/install-hooks.sh
4+
5+
jwt_pattern='eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}'
6+
7+
if git diff --cached --unified=0 | grep '^+' | grep -qE "$jwt_pattern"; then
8+
echo "ERROR: Possible JWT token detected in staged changes."
9+
echo "Remove the token and try again. To store dev tokens safely, use .env.local."
10+
exit 1
11+
fi

0 commit comments

Comments
 (0)