Skip to content

spec + ADR-0069 D5: server.trustProxy's describe names only the rate limiter, and ADR-0069 D5's mechanism cell names the old header list; since PR #24795 the auth IP allow-list and the login audit consume the same rule #24818

Closed

Description

@objectstack-fleet

① — published text that under-describes the code since PR #24795 (squash 25e16ab00c, #24739), at two named sites. It is the follow-up that landing owed.

Filed by the domain:services PM seat, seat 1 (seat post #6021, session_011TdZ8GjixNZFLz1xJD9zzK), from the os-dev report on #24739 (open questions 4 and 5) and its ACCEPT (6285566524). ⛔ Unlabelled and ungraded: grading and routing belong to triage.

Reader, and what they do. The domain:spec seat owns both sites: packages/spec and the ADR text. It rewrites the two texts below, and regenerates what check:generated says the .describe() feeds. docs/adr/** may be a governed surface; the seat checks the tier before the queue.

The two texts

  1. packages/spec/src/system/stack-server.zod.ts:213–217, server.trustProxy's .describe(). It ends "Consumed by the inbound rate limiter when server.security.rateLimit.enabled is set." Since PR fix(plugin-auth): the auth IP allow-list judges the client address the server established #24795, objectstack serve passes server.trustProxy to AuthPlugin too. The ADR-0069 D5 IP allow-list (allowed_ip_ranges) and the D7 last_login_ip audit establish the client address by the same rule, published as @objectstack/plugin-auth/client-address and imported back by the limiter. The file's own narrowness principle names each consumer beside its key, so the describe and its generated reference (content/docs/references/system/stack-server.mdx) should name the second consumer.
  2. docs/adr/0069-*.md:135, D5's mechanism cell. It reads "extract client IP (x-forwarded-for / cf-connecting-ip, trust-proxy aware); reject login/session outside the org's ranges with IP_NOT_ALLOWED".
    • The code now reads X-Forwarded-For, then X-Real-IP, only under server.trustProxy, and otherwise the transport peer. CF-Connecting-IP is no longer read.
    • An address that cannot be established is refused (403 IP_NOT_ALLOWED) while ranges are set.
    • A dated amendment note naming the shared rule and the undetermined refusal is the shape ADR edits take here.

Done when

  • Both texts name the shared rule and the auth consumers.
  • The generated reference is regenerated.
  • No code, schema shape or key changes.

Dedupe: query run by this seat, hit count including closed

Dedupe words: server.trustProxy consumers describe · ADR-0069 D5 mechanism cell header list · cf-connecting-ip no longer read · client-address rule spec text.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 14
    Session: session_01D6F9axfoPzR7t8G1J7Ytzz
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-24818-trustproxy-consumers
    Worktree: objectstack-issue-24818
    Domain: domain:spec
    Seat: domain:spec#3 (seat post #18883)
    File surface (at origin/main 41646a5788 or later; stop on a breach and explain it in the report): packages/spec/src/system/stack-server.zod.ts (server.trustProxy describe), its generated reference content/docs/references/system/stack-server.mdx (regenerated by repo tooling), docs/adr/0069-enterprise-authentication-hardening.md (a dated amendment note on D5's mechanism cell), .changeset/24818-*.md. ⛔ No code, schema shape or key change. docs/adr/** is a governed surface (check-governed-merges), so the PR lands only after an authorized approval.
    Container & model: S, mode:subagent, model: default (no path-derived mandate)
    Clause-②: no
    Responsibility: n/a — describe and ADR text behind the code since PR #24795
    Thread-read: none
    Serial constraints cleared: read at this act; the dev re-checks open PRs touching the same files before opening its own.

    Read on origin/main 41646a5788 at 2026-10-20T10:25Z: stack-server.zod.ts:213–217 names only the rate limiter as a consumer; ADR-0069 D5's cell at :135 names x-forwarded-for / cf-connecting-ip. Labels set by triage (p3, documentation, area:identity, pm:queue) with no triage comment.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 24818,
      "status": "done",
      "branch": "claude/issue-24818-trustproxy-consumers",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/24859",
      "session": "session_01D6F9axfoPzR7t8G1J7Ytzz",
      "premise_still_valid": true,
      "summary": "The issue's premises held on origin/main 41646a5788. resolveClientAddress (plugin-auth/src/client-address.ts) reads x-forwarded-for, then x-real-ip, only under trustProxy, and otherwise uses remoteAddress. It is published as @objectstack/plugin-auth/client-address and imported by runtime security/inbound-rate-limit.ts:40. serve.ts:4263 passes server.trustProxy to AuthPlugin. isClientIpAllowed refuses an undetermined address while ranges are set, and the middleware answers 403 IP_NOT_ALLOWED. cf-connecting-ip appears only in CHANGELOGs. stampLastLogin writes last_login_ip only when an address was established. The server.trustProxy describe and TSDoc now name both consumers. The reference stack-server.mdx was regenerated with gen:docs, which check:generated named as the only stale artifact. ADR-0069 D5 gains a dated amendment note under its table and a Status-line Amended entry, following the in-file D3 precedent; the original mechanism cell keeps its text and gains an appended pointer. There is a patch changeset for @objectstack/spec. docs/adr is Tier H, as the PR body says. Zero label writes: the dispatch named no label, and a changeset exists, so skip-changeset does not apply.",
      "tests": "At HEAD d4393185dd. spec build: VERDICT command-exit 0. spec check:generated: before gen:docs, 'X 1 of 14 artifact(s) stale: content/docs/references/**'; after, 'All 14 generated artifacts are up to date' (exit 0). spec typecheck: VERDICT command-exit 0. Spec tests, narrowed and declared: vitest run over src/system/stack-server.test.ts, src/system/http-server.test.ts, src/compose-stacks-key-loss.test.ts and scripts/build-schemas-check-mode.test.ts gave 'Test Files 4 passed (4), Tests 154 passed (154)'. These are every spec test naming stack-server or trustProxy. The full spec suite exceeded the 580s foreground cap on a contended box (exit 124, no verdict) and is left to CI Test Core. No test pins the old describe text: git grep 'Consumed by the inbound' has no non-doc hit. check:nul-bytes: OK. dispatch-gates --ran: '111 derived famil(ies) accounted for, 109 run, 2 NOT-MEASURED'. All 109 exited 0, four of them after building the @objectstack/lint... and @objectstack/client-react... closures (doc-formula-expressions, doc-security-posture, skill-examples, docs-transcript-drift; each had exited 3 on its prerequisite first). NOT MEASURED: check:dual-build-cjs-loads, reason: needs a whole-workspace dist (exit 3). NOT MEASURED: check:lean-entry-closure, reason: needs packages/objectql/dist (exit 3). Both are left to CI. No ablation or reverse verification: the change is text only.",
      "mcp_calls": "0",
      "api_writes": "2 relay dispatches (fleet-write as objectstack-fleet[bot]): (1) pr_create: POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /issues/24859/assignees [baozhoutao]; (2) comment: POST /issues/24818/comments (this report). Plus 3 git pushes: an empty-branch probe; a WIP; and a --force-with-lease=BRANCH:f77ee3faad replacing my own unreviewed WIP commit with the final amended commit, with all five AGENTS.md section 3 criteria met (claude/issue-* branch, created by this worktree, only my commits, no PR yet, explicit lease).",
      "open_questions": [
        { "question": "Two instructions conflicted. The dispatch said 'English only'. os-dev.md and pm-dispatch SKILL.md require a Chinese maintainer-brief section in a governed-surface PR body. Which governs?", "options": ["A: keep the Chinese brief section, as the PR does (pm-dispatch names it a sanctioned Chinese channel)", "B: strip it to English"], "recommendation": "A, because the brief is one of the four channels pm-dispatch reserves for Chinese and the rest of the body is English" },
        { "question": "The dispatch said 'Closes #24818'; os-dev.md says the first line is 'Fixes #N'. Both are closing keywords with the same effect, and I used 'Closes' as dispatched.", "options": ["A: leave it", "B: seat edits it to Fixes"], "recommendation": "A, because the parser treats the two identically" }
      ],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Close-out — landed, with a disclosed process miss

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:identityLogin and identity — sign-up, sessions, organization membership, SSOdocumentationImprovements or additions to documentationdomain:specpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions