docs: expand full-width guides and package navigation
This commit is contained in:
@@ -352,6 +352,17 @@ const registry = createDevToolbarRegistry();`,
|
||||
.join("");
|
||||
}
|
||||
|
||||
const packageNavigation = catalog
|
||||
.map(([name]) => `<a href="/packages/${name}">@wrnexus/${name}</a>`)
|
||||
.join("");
|
||||
const sectionNavigation = `<aside class="docs-section-menu" aria-label="Documentation sections"><nav>
|
||||
<section><strong>Get started</strong><a href="/getting-started">Quick start</a><a href="/tutorial">Tutorial</a><a href="/guides/full-stack-auth-demo">Auth dashboard demo</a><a href="/guides/configuration-and-profiles">Configuration</a></section>
|
||||
<section><strong>Build</strong><a href="/guides/pages-and-components">Pages and components</a><a href="/guides/routing">Routing</a><a href="/guides/server-data">Server data</a><a href="/guides/forms-and-validation">Forms and validation</a><a href="/guides/database">Database</a></section>
|
||||
<section><strong>Auth and security</strong><a href="/guides/authentication">Authentication</a><a href="/guides/authorization">Authorization</a><a href="/guides/security">Application security</a><a href="/security">Security policy</a></section>
|
||||
<section><strong>Reference</strong><a href="/packages">Packages overview</a><a href="/packages/cli">CLI</a><a href="/language">.wrn language</a><a href="https://component.wrnexusjs.dev/">Components</a><a href="/examples">Examples</a></section>
|
||||
<section class="package-menu"><strong>Packages</strong>${packageNavigation}</section>
|
||||
</nav></aside>`;
|
||||
|
||||
function shell(title: string, description: string, content: string, state = ""): string {
|
||||
const document = `page ${title.replace(/[^A-Za-z0-9]/g, "")} {
|
||||
seo {
|
||||
@@ -405,7 +416,7 @@ writeFileSync(
|
||||
shell(
|
||||
"Packages",
|
||||
"Explore every WrNexus package, API, function, and copy-ready usage example.",
|
||||
`<main class="page"><section class="hero compact"><span class="eyebrow">${catalog.length} focused packages</span><h1>Package reference</h1><p>Everything in the framework, organized by responsibility and documented from the published ${frameworkVersion} APIs.</p><input class="search" type="search" placeholder="Search packages, features, or categories…" @input="query = event.target.value" /></section><section class="category-filter" aria-label="Filter packages by category"><div class="category-row">${categoryButtons}</div><p>Showing <strong>{category}</strong> packages</p></section><section class="package-grid">${cards}</section></main>`,
|
||||
`<main id="main" class="portal-main docs-layout docs-layout--navigation">${sectionNavigation}<div class="docs-reading-column"><nav class="breadcrumbs" aria-label="Breadcrumb"><a href="/">Home</a><span>/</span><span aria-current="page">Packages</span></nav><article class="documentation prose standalone package-index-document"><section class="doc-intro"><span class="eyebrow">${catalog.length} focused packages</span><h1>Package reference</h1><p>Everything in the framework, organized by responsibility and documented from the published ${frameworkVersion} APIs.</p><input class="search" type="search" placeholder="Search packages, features, or categories…" @input="query = event.target.value" /></section><section id="filter" class="category-filter" aria-label="Filter packages by category"><h2>Find a package</h2><div class="category-row">${categoryButtons}</div><p>Showing <strong>{category}</strong> packages</p></section><section id="catalog"><h2>All packages</h2><div class="package-grid">${cards}</div></section></article></div><aside class="on-this-page"><h2>On this page</h2><nav><a href="#filter">Find a package</a><a href="#catalog">All packages</a></nav></aside></main>`,
|
||||
' state query = ""\n state category = "All"\n',
|
||||
),
|
||||
);
|
||||
@@ -440,8 +451,8 @@ for (const [name, category, summary] of catalog) {
|
||||
`<a class="toc-level-${heading.level}" href="#${heading.id}">${escape(heading.title)}</a>`,
|
||||
)
|
||||
.join("");
|
||||
const content = `<main class="portal-main docs-layout">
|
||||
<article id="main" class="documentation prose standalone package-document"><nav class="breadcrumbs" aria-label="Breadcrumb"><a href="/">Home</a><span>/</span><a href="/packages">Packages</a><span>/</span><span aria-current="page">@wrnexus/${name}</span></nav><section class="doc-intro"><span class="eyebrow">${category} · Package reference</span><h1>@wrnexus/${name}</h1><p>${summary}</p><div class="doc-meta"><span>v${frameworkVersion}</span><span>Private registry</span><span>${category}</span></div><section id="access" class="access-callout"><h2>Install the package</h2><p>After WorkRoot approves private registry access, install the release-aligned package:</p><pre><code>bun add @wrnexus/${name}@${frameworkVersion}</code><button type="button" class="copy-button" aria-label="Copy installation command">Copy</button></pre><p><a href="/access">Request preview access</a>. Never put registry tokens in source control.</p></section></section><section id="guide">${guide.html}</section><section id="api" class="api"><h2>Complete TypeScript API</h2><p>Generated from the exact installed package declarations.</p><pre data-language="typescript"><code>${escape(types)}</code></pre></section><section id="examples" class="examples"><h2>Examples</h2><p>Copy-ready examples from the installed package documentation.</p><div class="example-grid">${examplesFrom(readme, name)}</div></section>${componentReference}</article>
|
||||
const content = `<main id="main" class="portal-main docs-layout docs-layout--navigation">${sectionNavigation}<div class="docs-reading-column">
|
||||
<article class="documentation prose standalone package-document"><nav class="breadcrumbs" aria-label="Breadcrumb"><a href="/">Home</a><span>/</span><a href="/packages">Packages</a><span>/</span><span aria-current="page">@wrnexus/${name}</span></nav><section class="doc-intro"><span class="eyebrow">${category} · Package reference</span><h1>@wrnexus/${name}</h1><p>${summary}</p><div class="doc-meta"><span>v${frameworkVersion}</span><span>Private registry</span><span>${category}</span></div><section id="access" class="access-callout"><h2>Install the package</h2><p>After WorkRoot approves private registry access, install the release-aligned package:</p><pre><code>bun add @wrnexus/${name}@${frameworkVersion}</code><button type="button" class="copy-button" aria-label="Copy installation command">Copy</button></pre><p><a href="/access">Request preview access</a>. Never put registry tokens in source control.</p></section></section><section id="guide">${guide.html}</section><section id="api" class="api"><h2>Complete TypeScript API</h2><p>Generated from the exact installed package declarations.</p><pre data-language="typescript"><code>${escape(types)}</code></pre></section><section id="examples" class="examples"><h2>Examples</h2><p>Copy-ready examples from the installed package documentation.</p><div class="example-grid">${examplesFrom(readme, name)}</div></section>${componentReference}</article></div>
|
||||
<aside class="on-this-page"><h2>On this page</h2><nav>${toc}</nav></aside>
|
||||
</main>`;
|
||||
writeFileSync(join(packagePages, `${name}.wrn`), shell(`@wrnexus/${name}`, summary, content));
|
||||
|
||||
+231
-3
@@ -210,12 +210,16 @@ const documentationNavigation = [
|
||||
["/search", "Search"],
|
||||
] as const;
|
||||
|
||||
const packageNavigation = packageNames
|
||||
.map((name) => `<a href="/packages/${name}">@wrnexus/${name}</a>`)
|
||||
.join("");
|
||||
const sectionNavigation = `<aside class="docs-section-menu" aria-label="Documentation sections">
|
||||
<nav>
|
||||
<section><strong>Get started</strong><a href="/getting-started">Quick start</a><a href="/tutorial">Tutorial</a><a href="/guides/full-stack-auth-demo">Auth dashboard demo</a><a href="/guides/project-structure">Project structure</a><a href="/guides/configuration-and-profiles">Configuration</a></section>
|
||||
<section><strong>Build</strong><a href="/guides/pages-and-components">Pages and components</a><a href="/guides/routing">Routing</a><a href="/guides/server-data">Server data</a><a href="/guides/forms-and-validation">Forms and validation</a><a href="/guides/database">Database</a></section>
|
||||
<section><strong>Auth and security</strong><a href="/guides/authentication">Authentication</a><a href="/guides/authorization">Authorization</a><a href="/guides/security">Application security</a><a href="/security">Security policy</a></section>
|
||||
<section><strong>Reference</strong><a href="/packages">Packages</a><a href="/packages/cli">CLI</a><a href="/language">.wrn language</a><a href="https://component.wrnexusjs.dev/">Components</a><a href="/examples">Examples</a></section>
|
||||
<section><strong>Reference</strong><a href="/packages">Packages overview</a><a href="/packages/cli">CLI</a><a href="/language">.wrn language</a><a href="https://component.wrnexusjs.dev/">Components</a><a href="/examples">Examples</a></section>
|
||||
<section class="package-menu"><strong>Packages</strong>${packageNavigation}</section>
|
||||
</nav>
|
||||
</aside>`;
|
||||
|
||||
@@ -668,12 +672,222 @@ bunx wrnexus preview . --port=3000`)}<p>Tests should prove anonymous dashboard a
|
||||
<h2>9. Demo checklist</h2><ul><li>Public home, pricing, privacy, and terms pages render without authentication.</li><li>Login creates and rotates a secure session.</li><li>Dashboard navigation changes by permission, while APIs enforce every permission independently.</li><li>Member lists and mutations are tenant-scoped on the server.</li><li>Development and production profiles resolve explicitly.</li><li>Typecheck, API tests, browser tests, security audit, contract check, build, and preview all pass.</li></ul>`,
|
||||
],
|
||||
};
|
||||
const guideExamples: Record<string, [string, string]> = {
|
||||
"project-structure": [
|
||||
"Generate files through the CLI so routes and application types stay synchronized.",
|
||||
`bunx wrnexus generate page account/settings
|
||||
bunx wrnexus generate component account-card
|
||||
bunx wrnexus generate api account/profile
|
||||
bunx wrnexus generate routes
|
||||
bunx wrnexus generate types .`,
|
||||
],
|
||||
routing: [
|
||||
"This creates a dynamic, server-rendered account route and verifies that the router discovered it.",
|
||||
`// app/pages/accounts/[id].wrn
|
||||
page Account { view { <main><h1>Account {params.id}</h1></main> } }
|
||||
|
||||
bunx wrnexus inspect routes .`,
|
||||
],
|
||||
"pages-and-components": [
|
||||
"Declare the reusable contract in a component, then pass data from the owning page.",
|
||||
`component StatusCard {
|
||||
prop title = "Status"
|
||||
prop value = "Unknown"
|
||||
view { <article><h2>{title}</h2><p>{value}</p><slot /></article> }
|
||||
}
|
||||
|
||||
page Dashboard { view { <StatusCard title="API" value="Healthy" /> } }`,
|
||||
],
|
||||
"server-data": [
|
||||
"Fetch on the server and render useful HTML before browser JavaScript loads.",
|
||||
`page Accounts {
|
||||
ssr { api result GET /api/accounts { return result.accounts } }
|
||||
view { <ul>{#each result as account}<li>{account.name}</li>{:empty}<li>No accounts</li>{/each}</ul> }
|
||||
}`,
|
||||
],
|
||||
"api-routes": [
|
||||
"Validate a mutation and return an explicit HTTP result.",
|
||||
`import { v, parseBody } from "@wrnexus/validation";
|
||||
const input = v.object({ name: v.string().trim().min(2).max(80) });
|
||||
export const POST = async (ctx) => {
|
||||
const parsed = await parseBody(input, ctx.req);
|
||||
return parsed.ok ? Response.json(parsed.value, { status: 201 }) : parsed.response;
|
||||
};`,
|
||||
],
|
||||
middleware: [
|
||||
"Add a request identifier and reject unsupported methods before application handlers run.",
|
||||
`export default async function requestContext(ctx, next) {
|
||||
ctx.state.requestId = crypto.randomUUID();
|
||||
if (!["GET", "HEAD", "POST"].includes(ctx.req.method))
|
||||
return new Response("Method not allowed", { status: 405 });
|
||||
return next();
|
||||
}`,
|
||||
],
|
||||
"forms-and-validation": [
|
||||
"Use the same named schema in the browser form and authoritative API handler.",
|
||||
`page Signup { view {
|
||||
<form data-schema="signup" action="/api/signup" method="post">
|
||||
<input name="email" type="email" /><span data-error="email"></span>
|
||||
<button type="submit">Create account</button>
|
||||
</form>
|
||||
} }`,
|
||||
],
|
||||
authentication: [
|
||||
"Require an authenticated session in middleware and redirect browser requests to login.",
|
||||
`export default async function requireSession(ctx, next) {
|
||||
const user = await readAuthenticatedUser(ctx);
|
||||
if (!user) return Response.redirect(new URL("/login", ctx.url), 303);
|
||||
ctx.state.user = user;
|
||||
return next();
|
||||
}`,
|
||||
],
|
||||
authorization: [
|
||||
"Check the exact permission at the mutation boundary; hiding UI is only a convenience.",
|
||||
`export const DELETE = async (ctx) => {
|
||||
await requirePermission(ctx, "member:delete");
|
||||
await deleteMember(ctx.params.id, ctx.state.user.tenantId);
|
||||
return new Response(null, { status: 204 });
|
||||
};`,
|
||||
],
|
||||
security: [
|
||||
"Enable the main browser and request protections in application configuration, then audit the resolved production profile.",
|
||||
`// wrnexus.config.ts
|
||||
export default {
|
||||
security: {
|
||||
contentSecurityPolicy: true,
|
||||
csrf: true,
|
||||
trustedTypes: true,
|
||||
frameOptions: "deny",
|
||||
referrerPolicy: "strict-origin-when-cross-origin",
|
||||
requestLimit: { maxBytes: 1_048_576 },
|
||||
cors: { origins: ["https://app.example.com"] },
|
||||
},
|
||||
};
|
||||
|
||||
bunx wrnexus config . --explain --profile=production
|
||||
bunx wrnexus security audit .`,
|
||||
],
|
||||
database: [
|
||||
"Create a migration from models, apply it, and regenerate typed database functions.",
|
||||
`bunx wrnexus db status
|
||||
bunx wrnexus db new create_accounts --from-models
|
||||
bunx wrnexus db migrate
|
||||
bunx wrnexus db generate`,
|
||||
],
|
||||
uploads: [
|
||||
"Keep size and type policy server-owned and serve private objects through an authorized route.",
|
||||
`export default {
|
||||
uploads: { stores: { avatars: {
|
||||
driver: "local", directory: "./data/avatars",
|
||||
maxBytes: 2_000_000, accept: ["image/png", "image/jpeg"],
|
||||
} } },
|
||||
};`,
|
||||
],
|
||||
realtime: [
|
||||
"Authorize room membership and validate every incoming message before broadcasting.",
|
||||
`export default defineRoom("team", {
|
||||
async connect(client, ctx) { await requireTeamMember(ctx, ctx.params.teamId); },
|
||||
async message(client, raw) {
|
||||
const message = chatMessage.parse(JSON.parse(raw));
|
||||
client.room.broadcast(JSON.stringify(message));
|
||||
},
|
||||
});`,
|
||||
],
|
||||
pubsub: [
|
||||
"Use Redis when events must cross processes; use a namespaced channel contract.",
|
||||
`const bus = createRedisPubSub({ url: env.REDIS_URL });
|
||||
await bus.subscribe("team:42:events", (event) => handleTeamEvent(event));
|
||||
await bus.publish("team:42:events", JSON.stringify({ type: "member.invited" }));`,
|
||||
],
|
||||
queues: [
|
||||
"Make jobs idempotent and bound retry behavior before processing external effects.",
|
||||
`const emails = queue("emails", { concurrency: 4, retries: 3 });
|
||||
emails.process(async (job) => sendInviteOnce(job.data.invitationId));
|
||||
await emails.add({ invitationId }, { delay: 1_000 });`,
|
||||
],
|
||||
testing: [
|
||||
"Cover successful output and the denial path, then run the built server smoke check.",
|
||||
`import { describe, expect, test } from "bun:test";
|
||||
describe("members API", () => {
|
||||
test("denies anonymous requests", async () => {
|
||||
const response = await request("/api/members");
|
||||
expect(response.status).toBe(401);
|
||||
});
|
||||
});`,
|
||||
],
|
||||
"workspaces-and-gateway": [
|
||||
"Register applications explicitly and verify host routing through the gateway port.",
|
||||
`bunx wrnexus workspace company-platform
|
||||
cd company-platform
|
||||
bunx wrnexus workspace add admin --domain=admin.localhost
|
||||
bunx wrnexus gateway --port=3000`,
|
||||
],
|
||||
deployment: [
|
||||
"Build once, apply migrations before traffic, and run the immutable Bun server artifact.",
|
||||
`bun install --frozen-lockfile
|
||||
bunx wrnexus typecheck .
|
||||
bunx wrnexus db migrate
|
||||
bunx wrnexus build .
|
||||
bun dist/server.js`,
|
||||
],
|
||||
"configuration-and-profiles": [
|
||||
"Keep shared defaults at the root and make production differences explicit.",
|
||||
`export default {
|
||||
server: { port: 3000 },
|
||||
profiles: {
|
||||
development: { envFiles: [".env", ".env.development"] },
|
||||
production: { envFiles: [".env", ".env.production"] },
|
||||
},
|
||||
};
|
||||
|
||||
bunx wrnexus config . --explain --profile=production`,
|
||||
],
|
||||
"i18n-and-themes": [
|
||||
"Configure one default locale and theme, then reference translation keys in server-rendered markup.",
|
||||
`export default {
|
||||
i18n: { defaultLocale: "en", locales: ["en", "fr"] },
|
||||
theme: { default: "system", palette: "violet" },
|
||||
};
|
||||
|
||||
page Home { view { <h1>{t:home.title}</h1><button data-wire-theme-toggle>Theme</button> } }`,
|
||||
],
|
||||
mobile: [
|
||||
"Generate the mobile surface, compile it, and inspect supported native capabilities before relying on one.",
|
||||
`bunx wrnexus generate mobile
|
||||
bunx wrnexus mobile compile
|
||||
bunx wrnexus native list`,
|
||||
],
|
||||
observability: [
|
||||
"Redact credentials at the sink boundary and attach a stable request identifier.",
|
||||
`const tracking = createTracking({
|
||||
redact: ["authorization", "cookie", "password", "token"],
|
||||
sampleRate: 0.1,
|
||||
});
|
||||
export default tracking.middleware();`,
|
||||
],
|
||||
upgrading: [
|
||||
"Preview migrations first, review the report, then update the aligned package set.",
|
||||
`git status --short
|
||||
bunx wrnexus update . --latest --dry-run
|
||||
bunx wrnexus update . --latest
|
||||
bunx wrnexus typecheck .
|
||||
bunx wrnexus build .`,
|
||||
],
|
||||
troubleshooting: [
|
||||
"Collect deterministic diagnostics without exposing application secrets.",
|
||||
`bun --version
|
||||
bunx wrnexus doctor .
|
||||
bunx wrnexus config . --explain
|
||||
bunx wrnexus inspect routes .
|
||||
bunx wrnexus report . --file=app/pages/index.wrn`,
|
||||
],
|
||||
};
|
||||
for (const [slug, [title, desc, text]] of Object.entries(guides))
|
||||
page(
|
||||
`/guides/${slug}`,
|
||||
title,
|
||||
desc,
|
||||
`<article class="documentation prose standalone"><span class="status status-beta">Preview guide · ${version}</span><h1>${title}</h1>${text.startsWith("<") ? text : `<p>${text}</p>`}<h2>Configuration</h2><p>Keep configuration in <code>wrnexus.config.ts</code>, select an explicit profile, and store secrets only in validated environment variables. Use <code>wrnexus config . --explain</code> to review the resolved non-secret configuration.</p><h2>Implementation workflow</h2>${code(`bunx wrnexus doctor .
|
||||
`<article class="documentation prose standalone"><span class="status status-beta">Preview guide · ${version}</span><h1>${title}</h1>${text.startsWith("<") ? text : `<p>${text}</p>`}${guideExamples[slug] ? `<h2>Practical example</h2><p>${guideExamples[slug][0]}</p>${code(guideExamples[slug][1])}<h3>What to verify</h3><p>Run this against the selected profile, inspect the generated or returned result, and add a test for both the successful path and its most important failure path.</p>` : ""}<h2>Configuration</h2><p>Keep configuration in <code>wrnexus.config.ts</code>, select an explicit profile, and store secrets only in validated environment variables. Use <code>wrnexus config . --explain</code> to review the resolved non-secret configuration.</p><h2>Implementation workflow</h2>${code(`bunx wrnexus doctor .
|
||||
bunx wrnexus typecheck .
|
||||
bunx wrnexus inspect routes .
|
||||
bunx wrnexus build .`)}<p>Start from the exact installed package page, implement the smallest server-owned contract, and add browser behavior only where interaction requires it. Run the production build because development-only success does not prove deployability.</p><h2>Verification checklist</h2><ul><li>Inputs are validated at the authoritative server boundary.</li><li>Authentication and resource authorization are tested independently.</li><li>Generated routes and application types are current.</li><li>Error, empty, loading, denied, and success states are documented.</li><li>The production artifact starts and serves the expected route.</li></ul><h2>Release scope</h2><p>This guide describes installed ${version} capabilities. Follow linked package declarations for exact signatures; undocumented behavior is not guaranteed.</p><p><a href="/packages">Browse package APIs</a> · <a href="/packages/cli">CLI reference</a> · <a href="/guides/troubleshooting">Troubleshooting</a> · <a href="/support">Support</a></p></article>`,
|
||||
@@ -740,7 +954,21 @@ page(
|
||||
"/security",
|
||||
"Security",
|
||||
"WRNexusJS security defaults, limits, supported release status, and reporting process.",
|
||||
`<article class="documentation prose standalone"><h1>Security</h1><p>WRNexusJS provides primitives for CSP, CSRF, Trusted Types, sessions, validation, authorization, encryption, upload restrictions, request limits, and WebSocket-origin checks. Applications remain responsible for correct configuration, business authorization, secrets, dependencies, data protection, and operations.</p><h2>Supported releases</h2><p>Only the current private-preview release ${version} is documented here. A formal old-release support window is not yet published.</p><h2>Report a vulnerability</h2><p>Use WorkRoot’s approved private contact path at <a href="https://workroot.in/">workroot.in</a>. Do not publish exploit details or secrets. Include affected version, impact, reproduction, and a safe contact method. Response targets, encryption key, bounty, audit, and certification are not currently claimed.</p><h2>Deployment controls</h2><p>Use restrictive CSP and permissions policies, HSTS only on HTTPS production origins, MIME sniffing protection, restrictive referrers, explicit CORS, secure cookies, CSRF validation, request limits, and origin checks. See <a href="/guides/security">application security</a>.</p></article>`,
|
||||
`<article class="documentation prose standalone"><h1>Security</h1><p>WRNexusJS provides primitives for CSP, CSRF, Trusted Types, sessions, validation, authorization, encryption, upload restrictions, request limits, and WebSocket-origin checks. Applications remain responsible for correct configuration, business authorization, secrets, dependencies, data protection, and operations.</p><h2>Start with a production policy</h2><p>The following baseline blocks framing, restricts referrers and cross-origin access, enables CSRF and Trusted Types, and caps request bodies. Replace the example origin with the exact browser origin that calls your application.</p>${code(`// wrnexus.config.ts
|
||||
export default {
|
||||
security: {
|
||||
contentSecurityPolicy: true,
|
||||
csrf: true,
|
||||
trustedTypes: true,
|
||||
frameOptions: "deny",
|
||||
referrerPolicy: "strict-origin-when-cross-origin",
|
||||
cors: { origins: ["https://app.example.com"], credentials: true },
|
||||
requestLimit: { maxBytes: 1_048_576 },
|
||||
},
|
||||
};`)}<h3>What you can change</h3><ul><li>Add only required API origins to CORS; never use a wildcard with credentialed requests.</li><li>Lower request limits for JSON APIs and define separate upload limits for accepted file types.</li><li>Extend CSP only for origins your application actually loads; avoid unsafe inline script exceptions.</li><li>Enable HSTS only after HTTPS works on every production hostname and subdomain you include.</li><li>Set session expiry, rotation, secure, HTTP-only, and SameSite behavior for your authentication flow.</li></ul><h2>Verify the resolved controls</h2>${code(`bunx wrnexus config . --explain --profile=production
|
||||
bunx wrnexus security audit .
|
||||
bunx wrnexus typecheck .
|
||||
bunx wrnexus build .`)}<p>Review the resolved production configuration, then test a valid request, an invalid CSRF token, an oversized body, an unapproved origin, an anonymous protected request, and a permission-denied request. Security configuration is complete only when denial behavior is tested.</p><h2>Supported releases</h2><p>Only the current private-preview release ${version} is documented here. A formal old-release support window is not yet published.</p><h2>Report a vulnerability</h2><p>Use WorkRoot’s approved private contact path at <a href="https://workroot.in/">workroot.in</a>. Do not publish exploit details or secrets. Include affected version, impact, reproduction, and a safe contact method. Response targets, encryption key, bounty, audit, and certification are not currently claimed.</p><h2>Deployment controls</h2><p>Terminate TLS at a trusted edge, forward only expected proxy headers, store secrets outside source control, apply database migrations before traffic, and monitor rejected requests without logging credentials. Continue with the complete <a href="/guides/security">application security guide</a>.</p></article>`,
|
||||
"Trust",
|
||||
);
|
||||
page(
|
||||
|
||||
Reference in New Issue
Block a user