Tasks: gate-hosted-owner-exposure

tasks12/16
Created Updated openspec/changes/gate-hosted-owner-exposure/tasks.mdView on GitHub →

1. Owner-exposure posture (pure module)

  • 1.1 Add server/owner-exposure-posture.ts — a pure function deriving the posture from env + start options (no process.env reads inside, no server imports). Classify hosted via non-loopback PDPP_REFERENCE_ORIGIN / AS_PUBLIC_URL / asPublicUrl, NODE_ENV=production, or explicit non-loopback bindHost. Honor PDPP_HOSTED=1/0 and PDPP_ALLOW_UNAUTHENTICATED_OWNER=1. Ignore ambient hosting env under the Node test runner (isTestContext) so the suite stays hermetic.
  • 1.2 Unit tests pin the classification matrix and fail-closed decisions (test/owner-exposure-posture.test.js).

2. S-1 — close the owner-session bypass

  • 2.1 server/owner-auth.ts: add allowUnauthenticatedWhenDisabled option (default true for direct fixtures). When auth is disabled, fall through only if allowed; otherwise fail closed (401 JSON / /owner/login redirect).
  • 2.2 server/index.js: compute the posture in startServer and THROW before any listener binds when hosted + no password + no override. Log a loud warning when a local-dev posture still binds a non-loopback interface without a password.
  • 2.3 Wire the posture's allowUnauthenticatedOwnerWhenDisabled into createOwnerAuthPlaceholder via buildAsApp.
  • 2.4 Unit tests for the fail-closed branch (test/owner-auth-fail-closed.test.js).

3. S-2 — gate the connector registry

  • 3.1 server/routes/as-polyfill-connectors.ts: accept an optional requireOwnerSessionForRegister middleware and insert it before the POST /connectors handler when supplied. Leave GET /connectors/:id open.
  • 3.2 server/index.js: supply ownerAuth.requireOwnerSession for the register route only when the posture's lockConnectorRegistry is true (hosted or PDPP_LOCK_CONNECTOR_REGISTRY=1).

4. End-to-end proof

  • 4.1 Integration test (test/owner-hosted-exposure.test.js): hosted + no password → startServer rejects; hosted + password → unauthenticated POST /connectors is 401 and authenticated is 201; GET /connectors/:id stays open; local-dev POST /connectors stays open; override boots.

5. Gates

  • 5.1 New + existing owner-auth / owner-session / security / connector-route suites green.
  • 5.2 tsc --noEmit clean; biome check clean on changed files.
  • 5.3 openspec validate gate-hosted-owner-exposure --strict passes.

6. Out of scope (tracked separately)

  • 6.1 S-3 owner-session KDF (scrypt + per-server salt) — lane A3.
  • 6.2 S-4 / S-6 stderr-tail + connector-error redaction — lane A2.
  • 6.3 S-5 CIMD IP-guard hex-mapped/6to4 — lane A2.
  • 6.4 S-7 credential fingerprint width — lane A3.