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
29 changes: 26 additions & 3 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,24 +84,47 @@ jobs:
pnpm install --frozen-lockfile
pnpm build
- name: Install browser and Linux dependencies
if: (matrix.project == 'p4-editorial-publishing' || matrix.project == 'p5-dataguard' || matrix.project == 'p6-field-inspection' || matrix.project == 'p7-collaborative-docs' || matrix.project == 'p10-warehouse-workloads' || matrix.project == 'p11-saas-workspace' || matrix.project == 'p14-ai-scheduling-assistant') && runner.os == 'Linux'
if: (matrix.project == 'p1-task-manager' || matrix.project == 'p4-editorial-publishing' || matrix.project == 'p5-dataguard' || matrix.project == 'p6-field-inspection' || matrix.project == 'p7-collaborative-docs' || matrix.project == 'p10-warehouse-workloads' || matrix.project == 'p11-saas-workspace' || matrix.project == 'p14-ai-scheduling-assistant') && runner.os == 'Linux'
working-directory: ${{ matrix.project }}
run: pnpm exec playwright install --with-deps chromium
- name: Install browser
if: (matrix.project == 'p4-editorial-publishing' || matrix.project == 'p5-dataguard' || matrix.project == 'p6-field-inspection' || matrix.project == 'p7-collaborative-docs' || matrix.project == 'p10-warehouse-workloads' || matrix.project == 'p14-ai-scheduling-assistant') && runner.os != 'Linux'
if: (matrix.project == 'p1-task-manager' || matrix.project == 'p4-editorial-publishing' || matrix.project == 'p5-dataguard' || matrix.project == 'p6-field-inspection' || matrix.project == 'p7-collaborative-docs' || matrix.project == 'p10-warehouse-workloads' || matrix.project == 'p14-ai-scheduling-assistant') && runner.os != 'Linux'
working-directory: ${{ matrix.project }}
run: pnpm exec playwright install chromium
- name: Check
working-directory: ${{ matrix.project }}
run: pnpm check
- name: Run Linux integration scenario
if: runner.os == 'Linux' && (matrix.project == 'p3-mcp-capability-governance' || matrix.project == 'p8-cedarfile' || matrix.project == 'p9-cedarrealtime' || matrix.project == 'p11-saas-workspace' || matrix.project == 'p12-hr-access-governance' || matrix.project == 'p13-student-records' || matrix.project == 'p15-marketplace')
if: runner.os == 'Linux' && (matrix.project == 'p8-cedarfile' || matrix.project == 'p9-cedarrealtime' || matrix.project == 'p11-saas-workspace' || matrix.project == 'p12-hr-access-governance' || matrix.project == 'p13-student-records' || matrix.project == 'p15-marketplace')
working-directory: ${{ matrix.project }}
run: pnpm test:e2e
- name: Audit dependencies
working-directory: ${{ matrix.project }}
run: pnpm audit --audit-level low

p3-sidecar:
name: P3 signed-token sidecar workflow
needs: changes
if: contains(fromJSON(needs.changes.outputs.projects), 'p3-mcp-capability-governance')
runs-on: ubuntu-latest
timeout-minutes: 15
defaults:
run:
working-directory: p3-mcp-capability-governance
steps:
- uses: actions/checkout@v7.0.1
- uses: pnpm/action-setup@v6.1.0
with:
version: 10.17.1
run_install: false
- uses: actions/setup-node@v7.0.0
with:
node-version: 24.21.0
cache: pnpm
cache-dependency-path: p3-mcp-capability-governance/pnpm-lock.yaml
- run: pnpm install --frozen-lockfile
- run: pnpm test:e2e

compose-config:
name: Compose startup (${{ matrix.project }})
needs: changes
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ application that matches what you build. The projects run independently;
you do not need to complete them in order.

> [!NOTE]
> This checkout contains the tutorial starting applications. Marked authorization
> checks currently return `FAKE ALLOW`; the tutorials replace them with Cedarling
> decisions. Use these applications locally with sample data, not as production
> deployments.
> P1–P5 include Cedarling authorization. P6–P15 retain the tutorial starting
> applications, whose marked authorization checks return `FAKE ALLOW`.
> Use these applications locally with sample data, not as production deployments.

## Start with a task manager

Expand Down Expand Up @@ -87,6 +86,9 @@ P2 needs Voyage and OpenRouter credentials. P3's interactive chat runs in a
host terminal and needs Node.js, pnpm, and an OpenRouter key even when its
services run in Docker.

P3's Compose stack also runs its private Cedarling sidecar alongside the MCP
server and identity provider.

### With Node.js

Use **Node.js 24.21 or newer within 24.x** and **pnpm 10**. Follow the project's
Expand Down
2 changes: 2 additions & 0 deletions p1-task-manager/.prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
dist
coverage
pnpm-lock.yaml
test-results/
playwright-report/
5 changes: 4 additions & 1 deletion p1-task-manager/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ RUN corepack enable
WORKDIR /workspace/p1-task-manager
COPY p1-task-manager/package.json p1-task-manager/pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY shared/policy-store.mjs /workspace/shared/policy-store.mjs
COPY p1-task-manager/ ./
RUN pnpm build && pnpm prune --prod
RUN pnpm build \
&& pnpm prune --prod

FROM node:24.21.0-bookworm-slim AS runtime
ENV NODE_ENV=production P1_PROJECT_ROOT=/app
WORKDIR /app
COPY --from=build /workspace/p1-task-manager/package.json ./
COPY --from=build /workspace/p1-task-manager/node_modules ./node_modules
COPY --from=build /workspace/p1-task-manager/dist ./dist
COPY --from=build --chown=node:node /workspace/p1-task-manager/.local/policy-store.cjar ./.local/policy-store.cjar
RUN mkdir -p /app/.data && chown -R node:node /app/.data
USER node
EXPOSE 17001
Expand Down
53 changes: 33 additions & 20 deletions p1-task-manager/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
# P1 - Protecting a Node.js REST API with Cedarling

![Browser guidance and Fastify server enforcement with embedded Cedarling for task actions.](docs/assets/social-card.webp)

P1 is a multi-tenant task manager showing how Cedarling centralizes task
authorization inside a trusted Node.js API. Authentication, sessions, request
integrity, validation, tenant-scoped lists, and optimistic concurrency remain
application responsibilities.

The marked task capabilities currently use a fake permissive decision; the
Cedarling tutorial replaces that seam with policy-backed decisions.
The server enforces every protected task read and effect with Cedarling. The
browser evaluates the same policy release to hide controls conservatively,
while the server always makes the final decision.

## Architecture

Expand Down Expand Up @@ -42,19 +45,22 @@ For native development, run from this project directory:

```bash
pnpm --dir ../shared/identity-provider install --frozen-lockfile
pnpm --dir ../shared/identity-provider build
pnpm install --frozen-lockfile
pnpm run setup
node --env-file=.local/idp/.env ../shared/identity-provider/dist/main.js
```

Keep the IdP running. In another terminal in this project directory:

```bash
pnpm dev
```

For `pnpm build` followed by `pnpm start`, first run `node --env-file=.local/idp/.env ../shared/identity-provider/dist/main.js` in another terminal in this project directory.
`pnpm dev` prepares configuration and policies, starts this project's IdP,
and watches the browser and server together. Setup keeps the listen port aligned
with the registered application URL without resetting data.

For compiled startup, run `pnpm run setup`, `pnpm --dir ../shared/identity-provider build`,
and `pnpm build`. Keep `node --env-file=.local/idp/.env ../shared/identity-provider/dist/main.js`
running in another terminal, then run `pnpm start`.
Setup, build, and development startup validate the readable `policy-store/` source and create the ignored
`.local/policy-store.cjar` archive used by the Cedarling integration.
After editing policies, restart `pnpm dev` or rebuild before `pnpm start`.
The policy store trusts only issuer `http://localhost:18001` and audience
`http://localhost:17001/api`; setup and startup reject different values.

## Exercise

Expand All @@ -65,22 +71,29 @@ The business workflow is a shared task board:
- **Sam** — Tenant B external user who must remain isolated from Tenant A.

Compare their lists and mutations, including a direct task URL. The current
decision seam permits protected actions too broadly; Cedarling will decide each
task read and mutation from the actor, tenant, role, resource, and context.
policy permits Alex to view and edit assigned Tenant A work, gives Mina the
owner actions in Tenant A, and isolates Sam's Tenant B work. Browser state
cannot grant an operation that the server denies.

## Commands

| Command | Purpose |
| ---------------- | -------------------------------------------------- |
| `pnpm run setup` | Create validated native configuration and fixtures |
| `pnpm dev` | Build and watch the browser and server |
| `pnpm start` | Run the built server |
| `pnpm reset` | Restore synthetic local data |
| `pnpm check` | Run formatting, lint, types, tests, and build |
| Command | Purpose |
| ---------------- | ------------------------------------------------------------- |
| `pnpm run setup` | Create configuration and the local policy archive |
| `pnpm dev` | Start the IdP and watch the browser and server |
| `pnpm start` | Run the built server |
| `pnpm reset` | Restore synthetic local data |
| `pnpm test:e2e` | Build and test real browser/IdP authorization |
| `pnpm check` | Run formatting, lint, types, tests, build, and browser checks |

## Verify

```bash
pnpm exec playwright install chromium
pnpm check
pnpm audit --audit-level low
```

On Linux, use `pnpm exec playwright install --with-deps chromium` if browser
system libraries are missing. Browser checks use temporary credentials and data;
stop this project's running instances first so its ports are free.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added p1-task-manager/docs/assets/enforcement.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added p1-task-manager/docs/assets/meet-the-users.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added p1-task-manager/docs/assets/reusable-pattern.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added p1-task-manager/docs/assets/social-card.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading