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
2 changes: 1 addition & 1 deletion DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ A calm reading surface on the www.permit.io brand. Warm paper-like light surface

The source of truth is code: `src/css/tokens.scss` (brand and semantic tokens, with every contrast ratio), `src/css/base/_infima.scss` (tokens mapped onto Infima), `src/css/base/_typography.scss` (type scale), `src/css/components/*` (one partial per surface) and `src/css/prism/{light,dark}.js` (syntax colours). The frontmatter above mirrors those files; when they disagree, the SCSS wins and this file is stale.

**The Mirror Rule.** Brand tokens mirror `next-website/app/globals.css`. Change a brand value in both repos together, and record why here.
**The Mirror Rule.** Brand tokens mirror the www.permit.io website's global stylesheet. Change a brand value in both places together, and record why here.

## Colors

Expand Down
2 changes: 1 addition & 1 deletion STYLE_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ Use these terms, spelled this way.

## Content quality rules (technical-docs-writing)

This section adds the stricter rules of the technical-docs-writing standard. Where it and the sections above disagree, the stricter rule wins, except for the owner decisions listed at the end of this section. The page-by-page scores live in `docs-content-audit.md` at the repo root.
This section adds the stricter rules of the technical-docs-writing standard. Where it and the sections above disagree, the stricter rule wins, except for the owner decisions listed at the end of this section.

### One reader and one content type per page

Expand Down
2,237 changes: 0 additions & 2,237 deletions docs-content-audit.md

This file was deleted.

2 changes: 1 addition & 1 deletion docs/tutorials/_connecting_to_authentication.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ As mentioned above this is the first argument expected by [`permit.check()`](/ov
} )), 403
```

- [Authentication for a Nodejs Express app using Auth0](https://github.com/permitio/todoapp-node)
- Authentication for a Node.js Express app using Auth0
```js
router.post(
"",
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"scripts": {
"docusaurus": "docusaurus",
"start": "docusaurus start",
"build": "npm run redirect-lint && npm run links:relative && docusaurus build && cd build && echo '/2.0.0/* /:splat' > _redirects && npm run hyperlink && cd .. && npm run routes:check && npm run sidebars:check",
"build": "npm run redirect-lint && npm run links:relative && npm run paths:private && docusaurus build && cd build && echo '/2.0.0/* /:splat' > _redirects && npm run hyperlink && cd .. && npm run routes:check && npm run sidebars:check",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",
"clear": "docusaurus clear",
Expand All @@ -21,6 +21,7 @@
"hyperlink": "hyperlink ./build --check-anchors --sources ./docs",
"redirect-lint": "node checkRedirects",
"links:relative": "node scripts/check-relative-links.mjs",
"paths:private": "node scripts/check-private-paths.mjs",
"routes:write": "node scripts/route-inventory.mjs --write",
"routes:check": "node scripts/route-inventory.mjs --check",
"test:visual": "playwright test --project=visual-baseline",
Expand Down
481 changes: 0 additions & 481 deletions plans/2026-09-15-docs-site-makeover.md

This file was deleted.

2 changes: 1 addition & 1 deletion scripts/audit-a11y.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* 1. WCAG AA text contrast (4.5:1 normal text, 3.0:1 large text).
* 2. Content clipped outside the viewport at mobile width.
*
* Ported from next-website/scripts/audit-a11y.mjs. Elements whose visible
* Ported from the www.permit.io website's a11y audit. Elements whose visible
* colour comes from a clipped background gradient (`background-clip: text`
* with a transparent `color`) cannot be measured from the `color` property —
* reading it yields `transparent`, which computes to a false 1.05:1 failure.
Expand Down
38 changes: 38 additions & 0 deletions scripts/check-private-paths.fixtures.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Self-test lines for check-private-paths.mjs, which skips this file when it scans the
repo. `bad:` lines must be flagged, `good:` lines must not. The repo and directory
names below are placeholders, except the PRIVATE_REPOS names the script already lists.

Rule 1: GitHub links to a repo outside PUBLIC_REPOS.
bad: See https://github.com/permitio/some-private-service for details.
bad: [code](https://github.com/permitio/Some-Private-Service/blob/main/app.py)
bad: raw.githubusercontent.com/permitio/some-private-service/main/README.md
bad: | Source | github.com/permitio/some-private-service |
good: See https://github.com/permitio/opal for details.
good: [SDK](https://github.com/permitio/Permit-Python/tree/main/permit)
good: docker pull permitio/pdp-v2:latest
good: npm install @permitio/permit-node

Rule 2: a named private repo followed by a path.
bad: The logic lives in cloud-pdp/some-dir/src/main.rs.
bad: Verified in `permit-backend/some/dir/file.py`.
bad: **permit-opa/pkg/engine.go** does this.
bad: <text>next-website/app/page.tsx</text>
bad: | permit-frontend/src/app.tsx | yes |
bad: import x from "../permit-frontend/src/app";
bad: Checked in PERMIT-BACKEND/some/dir/file.py
bad: Checked in permitio/permit-backend some/dir/file.py
bad: Verified in permitio/cloud-pdp (some-dir/src, and more)
bad: Verified in cloud-pdp `some-dir/`
bad: Verified in `cloud-pdp` `some-dir/`
bad: See permit-backend:some/dir/file.py
good: ![Dashboard](/agent-security/dashboard.png)
good: kubectl logs -n agent-security deployment/agent-security-gateway --tail=20
good: helm install agent-security oci://registry.example.com/charts/agent-security
good: The cloud-pdp service answers checks.

Rule 3: repo-less source paths.
bad: The handler is in some-service/src/routes/handler.rs.
bad: Verified in `worker/src/config.rs`.
good: Colors come from Docusaurus's website/src/css/custom.css.
good: See https://example.com/app/src/index.ts for the example.
good: Edit src/css/tokens.scss for brand values.
182 changes: 182 additions & 0 deletions scripts/check-private-paths.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
// Fails the build when a tracked file cites Permit's private source code: a link to a
// private permitio repository, or a path inside one. This repo is public: such
// citations reveal internal structure and never help a docs reader (a link to a
// private repo is also a 404 for them). Describe the behavior, or link the public
// API reference, instead.
//
// Three rules, each case-insensitive:
//
// 1. GitHub links. A github.com or raw.githubusercontent.com URL under permitio/
// must name a repo in PUBLIC_REPOS. This catches every private repo without
// naming one; public names are safe to list. Docker Hub, npm and Terraform names
// also start with `permitio/`, so only those two hosts are checked. When you
// link a public repo that isn't listed yet, add it (lower case).
// 2. Named private repos. A PRIVATE_REPOS name that starts a path (<repo>/src/…),
// or is followed by a path in code formatting, parentheses or after a colon
// (<repo> `dir/`, <repo> (dir/…), <repo>:dir/…), or by a source-file path after
// plain whitespace (<repo> dir/file.py). The name must not follow a word
// character, `/` (except in `permitio/<repo>`), `.` or `-`, so site paths such
// as /agent-security/x.png pass, and so does a Helm release or namespace
// followed by a space (`-n agent-security deployment/…`).
// 3. Repo-less source paths: a lower-case `<dir>/src/<file>.<ext>` token outside a
// URL. ALLOWED_SRC_PATHS lists the public ones the docs cite on purpose.
//
// check-private-paths.fixtures.txt holds one known-bad line per shape and some
// known-good ones. Every run checks the rules against it first, so a rule change
// that stops catching a shape fails here instead of passing silently.
import { execFileSync } from "node:child_process";
import fs from "node:fs";

const PUBLIC_REPOS = new Set([
"admin-scripts",
"cedar-agent",
"cognito-integration",
"docs",
"galactic-health-corporation",
"generated-policy-example",
"ghc-demo-policy",
"langchain-permit",
"mesa-verde-banking-demo",
"n8n-nodes-permitio",
"opal",
"opal-example-policy-repo",
"pdp",
"permit-cli",
"permit-cpp",
"permit-demo-element",
"permit-dotnet",
"permit-erlang",
"permit-fe-sdk",
"permit-go-example",
"permit-golang",
"permit-hanko",
"permit-hasura-python-example",
"permit-java",
"permit-java-example",
"permit-kotlin",
"permit-langflow-framework",
"permit-mcp",
"permit-mongodb-secure-rag",
"permit-next-todo-starter",
"permit-node",
"permit-nuxt-example",
"permit-pdp-deployments-examples",
"permit-php",
"permit-prisma",
"permit-prompt-filtering",
"permit-pydanticai",
"permit-python",
"permit-python-example",
"permit-ruby",
"permit-vue-example",
"pink-mobile-demo-app",
"terraform-provider-permit-io",
"trino-authz-example",
]);
const PRIVATE_REPOS = [
"agent-security",
"cloud-pdp",
"next-website",
"pdp-tester",
"permit-backend",
"permit-frontend",
"permit-opa",
];
const ALLOWED_SRC_PATHS = [
// Docusaurus's own site source, cited in src/css/base/_infima.scss.
"website/src/",
];

const EXT = "py|rs|go|ts|tsx|js|jsx|mjs|cjs|rego|tpl|sql|sh|toml|ya?ml|json|css|scss|html";
const GITHUB_REPO =
/(?:github\.com|raw\.githubusercontent\.com)\/permitio\/([\w.-]+?)(?:\.git)?(?=[/)#?\s"'`\]>|,;]|$)/gi;
const START = String.raw`(?:^|[^\w/.-]|\.\./|permitio/)`;
const ANY_PATH = String.raw`[\w.-]+/`;
const SRC_PATH = String.raw`(?:\.{0,2}/)?(?:[\w.-]+/)*(?:src/[\w.-]+|[\w-]+\.(?:${EXT})\b)`;
const NAMED_REPO = new RegExp(
START +
`(${PRIVATE_REPOS.join("|")})` +
"(?:" +
[
String.raw`/[\w.-]`, // <repo>/path
String.raw`\x60?\s*[(:]\s*\x60?${ANY_PATH}`, // <repo> (path, <repo>:path
String.raw`\x60\s+\x60${ANY_PATH}`, // `<repo>` `path`
String.raw`\s+\x60${ANY_PATH}`, // <repo> `path`
String.raw`\x60?\s+\x60?${SRC_PATH}`, // <repo> dir/file.py
].join("|") +
")",
"i",
);
const REPOLESS_SRC = new RegExp(
String.raw`(?<![\w./:@-])[a-z][\w-]*/src/[\w./-]*[\w-]\.(?:${EXT})\b`,
"g",
);

// Returns [column, excerpt, reason] for the first problem on the line, or null.
function findProblem(line) {
for (const m of line.matchAll(GITHUB_REPO)) {
if (!PUBLIC_REPOS.has(m[1].toLowerCase()))
return [m.index, m[0], `links permitio/${m[1]}, which is not a known public repo`];
}
const named = line.match(NAMED_REPO);
if (named) return [named.index, named[0], `cites a path in the private ${named[1]} repo`];
for (const m of line.matchAll(REPOLESS_SRC)) {
if (!ALLOWED_SRC_PATHS.some((p) => m[0].startsWith(p)))
return [m.index, m[0], "cites a repo-relative source path"];
}
return null;
}

const SELF = "scripts/check-private-paths.mjs";
const FIXTURES = "scripts/check-private-paths.fixtures.txt";

// Self-test: `bad:` lines must be flagged, `good:` lines must not.
const selfTest = [];
fs.readFileSync(FIXTURES, "utf8")
.split("\n")
.forEach((line, i) => {
const [, kind, text] = line.match(/^(bad|good): (.*)$/) ?? [];
if (!kind) return;
if ((kind === "bad") !== Boolean(findProblem(text)))
selfTest.push(` ${FIXTURES}:${i + 1}: expected ${kind}: ${text}`);
});
if (selfTest.length) {
console.error(
`paths:private self-test failed; the rules no longer match:\n${selfTest.join("\n")}`,
);
process.exit(1);
}

const SKIP = /\.(png|jpe?g|gif|webp|ico|mp4|woff2?|ttf|pdf)$|^package-lock\.json$/i;
const files = execFileSync("git", ["ls-files", "-z"], { encoding: "utf8" })
.split("\0")
.filter(
(f) =>
f &&
f !== SELF &&
f !== FIXTURES &&
!SKIP.test(f) &&
fs.existsSync(f) &&
fs.statSync(f).isFile(),
);

const problems = [];
for (const file of files) {
fs.readFileSync(file, "utf8")
.split("\n")
.forEach((line, i) => {
const found = findProblem(line);
if (!found) return;
const [col, excerpt, reason] = found;
problems.push(`${file}:${i + 1}:${col + 1}: ${reason}: ${excerpt.trim().slice(0, 80)}`);
});
}

if (problems.length) {
console.error(
`Private source citations in tracked files (${problems.length}). This repo is public; remove them:\n` +
problems.map((p) => ` ${p}`).join("\n"),
);
process.exit(1);
}
console.log(`paths:private: ${files.length} tracked files, no private source citations`);
2 changes: 1 addition & 1 deletion src/components/diagrams/DecisionFlowDiagram.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Link from "@docusaurus/Link";
import DiagramFrame, { DecisionReceipt } from "./DiagramFrame";
import styles from "./diagrams.module.scss";

// Ported from next-website/components/diagrams/DecisionFlowDiagram.tsx. Each
// Ported from the www.permit.io website's decision-flow diagram. Each
// stage title links to the docs page that explains that step.
const STAGES = [
{
Expand Down
2 changes: 1 addition & 1 deletion src/components/diagrams/DiagramFrame.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import styles from "./diagrams.module.scss";

/**
* Shared shell for coded architecture diagrams, ported from
* next-website/components/diagrams/DiagramFrame.tsx. Diagrams are real markup,
* the www.permit.io website's diagram frame. Diagrams are real markup,
* not images, so labels stay accurate, readable by screen readers and search,
* and correct in both themes.
*
Expand Down
2 changes: 1 addition & 1 deletion src/components/diagrams/HybridDeploymentDiagram.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Link from "@docusaurus/Link";
import DiagramFrame from "./DiagramFrame";
import styles from "./diagrams.module.scss";

// Ported from next-website/components/diagrams/HybridDeploymentDiagram.tsx.
// Ported from the www.permit.io website's hybrid-deployment diagram.
// Claims follow docs/overview/how-does-it-work.mdx (control plane in Permit's
// cloud, PDPs in your network, OPAL keeps them in sync, decisions do not
// depend on Permit's availability).
Expand Down
6 changes: 3 additions & 3 deletions src/components/diagrams/McpGatewayPathDiagram.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import Link from "@docusaurus/Link";
import DiagramFrame from "./DiagramFrame";
import styles from "./diagrams.module.scss";

// The request path of one MCP tool call through Permit MCP Gateway. Adapted
// from next-website DefenseInDepthDiagram / AgenticIdentityDiagram; every
// label follows docs/permit-mcp-gateway/architecture.mdx, consent-service.mdx,
// The request path of one MCP tool call through Permit MCP Gateway. Adapted from
// the www.permit.io website's defense-in-depth and agentic-identity diagrams;
// every label follows docs/permit-mcp-gateway/architecture.mdx, consent-service.mdx,
// permit-integration.mdx and audit-logs.mdx.
const HOPS = [
{
Expand Down
10 changes: 5 additions & 5 deletions src/css/prism/dark.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Prism dark theme for code blocks, from the www.permit.io code palette
// (next-website/styles/prism-theme.css). The website draws these colours on a
// warm #2a211f; here they sit on the dark code surface (--pm-code-bg =
// --pm-surface-1, #0a0f22) and on a highlighted line (brand purple #875cff at
// 16% over that surface = #1e1b45). Change both files together.
// Prism dark theme for code blocks, from the www.permit.io website's prism theme.
// The website draws these colours on a warm #2a211f; here they sit on the dark
// code surface (--pm-code-bg = --pm-surface-1, #0a0f22) and on a highlighted line
// (brand purple #875cff at 16% over that surface = #1e1b45). Change this file,
// light.js and the website's prism theme together.
//
// WCAG 2.x contrast, text on code bg #0a0f22 highlighted line #1e1b45
// plain #f9ede7 16.57 14.05
Expand Down
4 changes: 2 additions & 2 deletions src/css/tokens.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// src/css/tokens.scss — values mirror next-website/app/globals.css (--neon-purple-rgb,
// --neon-orange-rgb, --deep-bg, --surface-1..3). Change both together.
// src/css/tokens.scss — values mirror the www.permit.io website's global stylesheet
// (--neon-purple-rgb, --neon-orange-rgb, --deep-bg, --surface-1..3). Change both together.
//
// Brand tokens (the `--pm-*` block the website shares) come first, then the
// docs-only semantic tokens derived from them. Components consume tokens or
Expand Down
2 changes: 1 addition & 1 deletion src/data/site-links.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Single source for links that leave the docs: navbar, footer, and any component
// that points at the website, the app, or the community. Mirrors
// next-website/components/layout/navbar-links.ts; change both together.
// the www.permit.io website's navbar links; change both together.
//
// API_REFERENCE is the ReDoc URL the docs already use (the pre-split sidebar
// header block and ~110 links in docs/**). api.permit.io/scalar also serves the
Expand Down
Loading