Skip to content

PAY-001A — Add bounded request validation and safe logging primitives #157

Closed

Description

@daliu

Officer impact: No current officer screen or procedure changes. This adds a reusable server safety layer so later race registration, merchandise, refund, and admin commands can reject malformed input before touching Firebase or Stripe.

Officer documentation: None — this atomic child is a pure server library with no public or officer-visible behavior. Later endpoint-wiring children must update the affected officer procedures.

Deployment evidence: None at issue creation. Closure proves source, tests, review, merge, and exact-commit CI only. No endpoint uses these helpers yet; no website, Firebase, Stripe, provider, or production behavior may be called deployed or verified.

Parent and dependencies

Atomic PAY-001A child of catalogued PAY-001 in GITHUB_ISSUES.md and GITHUB_ISSUE_SLICES.md.

This child unlocks PAY-001B/C/D and PAY-002A. It does not wire any endpoint.

Problem

Current Functions validate inputs inconsistently. A future payment or admin command could accept arrays as objects, inherited/prototype fields, unexpected keys, excessive nesting, unsafe money, malformed dates or URLs, oversized text, or sensitive/high-cardinality logging fields.

Endpoint-by-endpoint fixes would drift. We need small pure CommonJS primitives with exhaustive hostile-input tests before those endpoints are migrated.

Atomic outcome

Add two dependency-free server libraries:

  1. requestValidation: strict plain-object and own-property validation; unknown-key rejection; bounded depth/field/string/array helpers; safe nonnegative integer cents; explicit currency normalization; strict dates; HTTPS and explicitly allowed loopback URLs; bounded normalized email; fixed public-safe validation errors.
  2. safeLogging: build a new immutable structured-log projection from an explicit allowlist of low-cardinality fields and fixed safe values. Caller-supplied bodies, arbitrary keys, tokens, URLs, addresses, contact fields, Stripe/OAuth material, and raw errors are never copied.

Security invariants

  • Reject null, arrays-as-objects, class instances, symbol keys, accessors, inherited enumerable fields, and dangerous own keys such as __proto__, prototype, and constructor.
  • Validation is deterministic, bounded, and has no Firebase, Stripe, network, clock, randomness, logging, or mutation side effect.
  • Reject unsafe, fractional, negative, signed-string, exponent, boolean, NaN, Infinity, and over-limit monetary values.
  • Currency is explicit and allowlisted; no locale guessing or floating-point conversion.
  • Dates are strict canonical values with calendar round-trip checks; URLs are HTTPS except an explicit test/development loopback option.
  • Email normalization is bounded and conservative; it is syntax validation, not account identity or deliverability proof.
  • Public errors use fixed categories/messages and never include the supplied value, field contents, provider details, stack, or raw error.
  • Structured logs are constructed from explicit safe fields; no recursive “redaction” of an unsafe object and no caller-selected log keys.
  • Results are new immutable values. Input objects are never modified.
  • Tests use hostile synthetic canaries only and make no external call.

Exact source boundary

  • New functions/requestValidation.js
  • New functions/requestValidation.test.js
  • New functions/safeLogging.js
  • New functions/safeLogging.test.js
  • Minimum exact status/design hunks in:
    • STRIPE_COMMERCE_DESIGN.md
    • SECURITY.md
    • GITHUB_ISSUES.md
    • GITHUB_ISSUE_SLICES.md
    • IMPLEMENTATION_PLAN.md

Post a scope amendment before editing existing endpoints, stripeHelpers.js, serverConfig.js, commerceControl.js, package/lockfiles, Rules, client code, workflows, officer guides, providers, deployment configuration, or production data.

Acceptance criteria

  • Strict-object tests reject arrays, instances, symbols, accessors, inherited fields, dangerous keys, and every unknown own key.
  • Bound tests cover depth, total field count, arrays, strings, Unicode normalization/length, and hostile HTML without executing or logging it.
  • Money tests cover zero/max, negative, fractional, unsafe, string/exponent, boolean, and invalid/unsupported currency values.
  • Date, URL, and email tests cover canonical positives and malformed, oversized, encoded, credential-bearing, non-HTTPS, and loopback boundaries.
  • Safe errors have fixed codes/messages and never echo a hostile canary or raw error.
  • Safe log projections accept only documented low-cardinality fields and cannot emit bodies, arbitrary keys, tokens, URLs, addresses, email, phone, Stripe/OAuth values, or hostile canaries.
  • Returned objects/arrays are frozen or otherwise immutable; inputs remain byte/deep equivalent and unfrozen.
  • Tests deliberately fail if any external Firebase/Stripe/network/logger dependency is introduced or called.
  • Node 20 focused tests, full Functions lint/tests, hosted CI, diff/sensitive-pattern review, and independent review pass.
  • Root design/status docs say the primitives are merged only after merge and say endpoint adoption/deployment/live behavior remain NOT AVAILABLE YET.

Excluded

Claim protocol

Creation is not a claim. Before editing: confirm the exact current-main SHA, assign the issue, post CLAIMED by /root at <UTC>; branch codex/issue-<number>-request-safety-primitives, apply status:in-progress, and use an isolated worktree. One atomic source/test outcome at a time.

Activity

  1. self-assigned this
    on Jul 13, 2026
  2. added
    priority:P0Launch blocker or urgent security risk
    type:securitySecurity or privacy boundary
    size:MMedium multi-file issue
    area:stripeStripe payments and financial lifecycle
    status:in-progressClaimed and actively being implemented
    on Jul 13, 2026
  3. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    CLAIMED by /root at 2026-07-13T13:41:24Z; branch codex/issue-157-request-safety-primitives; exact base 594306f. Exact source boundary is the four new pure Functions library/test files plus minimum five root-document status/design hunks. Existing endpoints, packages, Rules, client, workflows, providers, deployment, and production data remain immutable.

  4. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    EXTRACTION FINISHED by /root at 2026-07-13T14:24:50Z.

    • Branch: codex/issue-157-request-safety-primitives
    • Exact base: 594306fb06d9a6a2a44b5675b305f462f11b877d
    • Exact staged diff hash: 508145eaefc972fd6bcc0b2778961c3091f0a032
    • Scope: exactly the four new Functions library/test files and five approved root status/design documents.
    • Node 20 focused proof: 2 suites, 179 tests passed.
    • Node 20 full Functions proof: 11 suites passed, 1 intentionally skipped; 457 passed, 1 skipped.
    • Functions ESLint and both staged/worktree diff checks passed.
    • Three independent reviews approved the final code/security, adversarial test, and documentation boundaries.
    • Sensitive-pattern scan found no live secret-shaped credential or private key.
    • Officer impact: no current screen or procedure changes.
    • Officer documentation: None — this is a pure server library with no endpoint adoption.
    • Deployment evidence: source/tests/review only. No endpoint imports these helpers; no website, Firebase, Stripe, provider, or production behavior was deployed or verified.

    Next state is commit and pull-request review. PAY-001B/C/D, endpoint schemas, nested exact schemas, immutable snapshots, deployment, and live protection remain open.

  5. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    COMPLETED by /root at 2026-07-13T14:32:43Z.

    • PR PAY-001A: add bounded request validation and safe logging #158 merged by authorized admin squash as exact main e5a0390f8c1c9dc9a51f83457cd3623ea0bc9723.
    • Exact-head PR CI 29257925973 passed Frontend, Cloud Functions, and Firestore Rules.
    • Exact-main post-merge CI 29258229819 passed the same three jobs.
    • Local Node 20 focused proof was 179/179; full Functions proof was 457 passed with 1 intentionally skipped; lint passed.
    • Three independent reviews approved security/correctness, hostile-input behavior, and documentation truth.
    • Every issue acceptance box is now checked.
    • Deployment evidence: no runtime deployment was applicable or performed. No current endpoint imports these helpers, so website/Firebase/Stripe/provider/live protection remains unproven and must not be inferred from CI.
    • PAY-001 remains partial. PAY-001B/C/D, endpoint/nested schemas, immutable snapshots, and protected deployment stay open.
    • The timestamped PAY-001A — Add bounded request validation and safe logging primitives #157 file claim is released at main e5a0390f.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:stripeStripe payments and financial lifecyclepriority:P0Launch blocker or urgent security risksize:MMedium multi-file issuetype:reliabilityReliability and recoverytype:securitySecurity or privacy boundary

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions